Activadores de Firestore

Puedes configurar tus funciones de Cloud Run para que se activen con eventos en una base de datos de Firestore. Una vez activada, tu función puede leer y actualizar una base de datos de Firestore en respuesta a estos eventos a través de las APIs de Firestore y las bibliotecas cliente.

En un ciclo de vida típico, una función de Firestore hace lo siguiente:

  1. Espera a que ocurran cambios en un documento en particular.

  2. Se activa cuando ocurre un evento y realiza sus tareas.

  3. Recibe un objeto de datos con una instantánea del documento afectado. En el caso de los eventos write o update, el objeto de datos contiene instantáneas que representan el estado del documento antes y después del evento de activación.

Tipos de eventos

Firestore admite los eventos create, update, delete y write. El evento write comprende todas las modificaciones que se realizan a un documento.

Tipo de evento Activador
google.cloud.firestore.document.v1.created (predeterminada) Se activa cuando se escribe en un documento por primera vez.
google.cloud.firestore.document.v1.updated Se activa cuando un documento ya existe y se cambia uno de sus valores.
google.cloud.firestore.document.v1.deleted Se activa cuando se borra un documento con datos.
google.cloud.firestore.document.v1.written Se activa cuando se crea, actualiza o borra un documento.

Los comodines se escriben en los activadores con llaves, como se muestra en el siguiente ejemplo: "projects/YOUR_PROJECT_ID/databases/(default)/documents/collection/{document_wildcard}"

Especifica la ruta del documento

Para activar tu función, especifica una ruta de acceso al documento que deseas escuchar. La ruta de acceso al documento debe estar en el mismo proyecto de Google Cloud que la función.

A continuación, se muestran algunos ejemplos de rutas de acceso de documentos válidas:

  • users/marie: Activador válido. Supervisa un solo documento, /users/marie.

  • users/{username}: activador válido. Supervisa todos los documentos del usuario. Los comodines se usan para supervisar todos los documentos de la colección.

  • users/{username}/addresses: activador no válido. Se refiere a la subcolección addresses, no a un documento.

  • users/{username}/addresses/home: activador válido. Supervisa el documento de dirección particular de todos los usuarios.

  • users/{username}/addresses/{addressId}: activador válido. Supervisa todos los documentos de dirección.

  • users/{user=**}: Activador válido. Supervisa todos los documentos del usuario y los documentos de las subcolecciones de cada documento del usuario, como /users/userID/address/home o /users/userID/phone/work.

Comodines y parámetros

Si no conoces el documento específico que quieres supervisar, usa un {wildcard} en lugar del ID del documento:

  • users/{username} escucha cambios en todos los documentos del usuario.

En este ejemplo, cuando se cambia cualquier campo en los documentos de users, coincide con un comodín llamado {username}.

Si un documento de users tiene subcolecciones y se modifica un campo de uno de los documentos en ellas, no se activará el comodín {username}. Si tu objetivo es responder también a los eventos en las subcolecciones, usa el comodín de varios segmentos {username=**}.

Las coincidencias de comodines se extraen de las rutas de acceso de documentos. Puedes definir tantos comodines como desees para sustituir los IDs explícitos de colección o documento. Puedes usar hasta un comodín de varios segmentos, como {username=**}.

Estructuras de eventos

Este activador invoca tu función con un evento similar al siguiente:

{
    "oldValue": { // Update and Delete operations only
        A Document object containing a pre-operation document snapshot
    },
    "updateMask": { // Update operations only
        A DocumentMask object that lists changed fields.
    },
    "value": {
        // A Document object containing a post-operation document snapshot
    }
}

Cada objeto Document contiene uno o más objetos Value. Consulta la documentación de Value para obtener referencias de tipo. Esto resulta muy útil si usas un lenguaje escrito (como Go) para escribir tus funciones.

Ejemplos

En los siguientes ejemplos, se muestra cómo escribir funciones que respondan a un activador de Firestore.

Antes de comenzar

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Logging, Pub/Sub, and Cloud Run APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Functions, Cloud Build, Artifact Registry, Eventarc, Logging, Pub/Sub, and Cloud Run APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. Si ya tienes instalado gcloud CLI, ejecuta el siguiente comando para actualizarla:

    gcloud components update
  13. Prepara tu entorno de desarrollo.

Configura la base de datos de Firestore

Necesitas una base de datos de Firestore para probar las muestras en este documento. Debe estar en su lugar antes de implementar las funciones. Si aún no está lista la base de datos de Firestore, crea una de la siguiente manera:

  1. Ir a la página de Datos de Firestore.

  2. Haz clic en Elegir modo nativo.

  3. Elige la región (ubicación) en la que residirá tu base de datos. Esta elección es permanente.

  4. Haz clic en Crear base de datos.

El modelo de datos de Firestore consta de colecciones que contienen documentos. Cada documento contiene un conjunto de pares clave-valor.

Las funciones que creas en este instructivo se activan cuando realizas cambios en un documento dentro de una colección especificada.

Ejemplo 1: Función Hola Firestore

En la siguiente función de Cloud Run de muestra, se imprimen los campos de un evento de activación de Firestore:

Node.js

Usa protobufjs para decodificar los datos del evento. Incluye el google.events.cloud.firestore.v1 data.proto en la fuente.

/**
 * Cloud Event Function triggered by a change to a Firestore document.
 */
const functions = require('@google-cloud/functions-framework');
const protobuf = require('protobufjs');

functions.cloudEvent('helloFirestore', async cloudEvent => {
  console.log(`Function triggered by event on: ${cloudEvent.source}`);
  console.log(`Event type: ${cloudEvent.type}`);

  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  console.log('\nOld value:');
  console.log(JSON.stringify(firestoreReceived.oldValue, null, 2));

  console.log('\nNew value:');
  console.log(JSON.stringify(firestoreReceived.value, null, 2));
});

Python

from cloudevents.http import CloudEvent
import functions_framework
from google.events.cloud import firestore


@functions_framework.cloud_event
def hello_firestore(cloud_event: CloudEvent) -> None:
    """Triggers by a change to a Firestore document.

    Args:
        cloud_event: cloud event with information on the firestore event trigger
    """
    firestore_payload = firestore.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    print(f"Function triggered by change to: {cloud_event['source']}")

    print("\nOld value:")
    print(firestore_payload.old_value)

    print("\nNew value:")
    print(firestore_payload.value)

Go


// Package hellofirestore contains a Cloud Event Function triggered by a Cloud Firestore event.
package hellofirestore

import (
	"context"
	"fmt"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

func init() {
	functions.CloudEvent("helloFirestore", HelloFirestore)
}

// HelloFirestore is triggered by a change to a Firestore document.
func HelloFirestore(ctx context.Context, event event.Event) error {
	var data firestoredata.DocumentEventData

	// If you omit `DiscardUnknown`, protojson.Unmarshal returns an error
	// when encountering a new or unknown field.
	options := proto.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err := options.Unmarshal(event.Data(), &data)

	if err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	fmt.Printf("Function triggered by change to: %v\n", event.Source())
	fmt.Printf("Old value: %+v\n", data.GetOldValue())
	fmt.Printf("New value: %+v\n", data.GetValue())
	return nil
}

Java

import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.logging.Logger;

public class FirebaseFirestore implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestore.class.getName());

  @Override
  public void accept(CloudEvent event) throws InvalidProtocolBufferException {
    DocumentEventData firestoreEventData = DocumentEventData
        .parseFrom(event.getData().toBytes());

    logger.info("Function triggered by event on: " + event.getSource());
    logger.info("Event type: " + event.getType());

    logger.info("Old value:");
    logger.info(firestoreEventData.getOldValue().toString());

    logger.info("New value:");
    logger.info(firestoreEventData.getValue().toString());
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseFirestore;

public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;

    public Function(ILogger<Function> logger) =>
        _logger = logger;

    public Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Function triggered by event on {subject}", cloudEvent.Subject);
        _logger.LogInformation("Event type: {type}", cloudEvent.Type);
        MaybeLogDocument("Old value", data.OldValue);
        MaybeLogDocument("New value", data.Value);

        // In this example, we don't need to perform any asynchronous operations, so the
        // method doesn't need to be declared async.
        return Task.CompletedTask;
    }

    /// <summary>
    /// Logs the names and values of the fields in a document in a very simplistic way.
    /// </summary>
    private void MaybeLogDocument(string message, Document document)
    {
        if (document is null)
        {
            return;
        }

        // ConvertFields converts the Firestore representation into a .NET-friendly
        // representation.
        IReadOnlyDictionary<string, object> fields = document.ConvertFields();
        var fieldNamesAndTypes = fields
            .OrderBy(pair => pair.Key)
            .Select(pair => $"{pair.Key}: {pair.Value}");
        _logger.LogInformation(message + ": {fields}", string.Join(", ", fieldNamesAndTypes));
    }
}

Implementa la función Hola Firestore

  1. Si aún no está lista, configura la base de datos de Firestore.

  2. Para ejecutar la función de Hola Firestore con un activador de Firestore, ejecuta el siguiente comando en el directorio que contiene el código de muestra (o, en el caso de Java, el archivo pom.xml):

    gcloud functions deploy FUNCTION_NAME \
    --gen2 \
    --runtime=RUNTIME \
    --region=REGION \
    --trigger-location=TRIGGER REGION \
    --source=. \
    --entry-point=ENTRY_POINT \
    --trigger-event-filters=type=google.cloud.firestore.document.v1.written \
    --trigger-event-filters=database='(default)' \
    --trigger-event-filters-path-pattern=document='users/{username}'

    Reemplaza lo siguiente:

    • FUNCTION_NAME: un nombre para la función implementada.
    • RUNTIME: el entorno de ejecución de lenguaje que usa tu función.
    • REGION: la región en la que se implementará la función.
    • TRIGGER_REGION: La ubicación del activador, que debe ser la misma que la región de la base de datos de Firestore.
    • ENTRY_POINT: el punto de entrada a tu función en tu código fuente. Este es el código que se ejecuta cuando se ejecuta tu función.

    Usa los otros campos tal como están:

    • --trigger-event-filters=type=google.cloud.firestore.document.v1.written especifica que la función se activa cuando se crea, actualiza o borra un documento, según el tipo de evento google.cloud.firestore.document.v1.written.
    • --trigger-event-filters=database='(default)' especifica la base de datos de Firebase. Para ver el nombre de la base de datos predeterminada, usa (default).
    • --trigger-event-filters-path-pattern=document='users/{username}' proporciona el patrón de ruta de acceso de los documentos que deben supervisarse para detectar cambios relevantes. En este patrón de ruta de acceso, se indica que se deben supervisar todos los documentos de la colección users. Para obtener más información, consulta Información sobre los patrones de ruta de acceso.

Prueba la función Hola Firestore

Para probar la función Hola Firestore, configura una colección llamada users en tu base de datos de Firestore:

  1. En la página de datos de Firestore, haz clic en Iniciar una colección.

  2. Especifica users como el ID de colección.

  3. Para empezar a agregar el primer documento de la colección, en Agregar su primer documento, acepta el ID de documento generado de forma automática.

  4. Agrega al menos un campo para el documento y especifica un nombre y un valor. En este ejemplo, el nombre es “username” y el valor es “rowan:”

    Captura de pantalla que muestra cómo crear una colección de Firestore

  5. Cuando termines, haz clic en Guardar.

    Esta acción crea un documento nuevo, lo que activa tu función.

  6. Para confirmar que tu función se activó, haz clic en el nombre vinculado de la función en la consola de Google Cloud.Página de resumen de Cloud Run Functions para abrir la página Detalles de la función.

  7. Abre la pestaña Registros y busca esta cadena:

Function triggered by change to: //firestore.googleapis.com/projects/your-project-id/databases/(default)'

Ejemplo 2: función Convertir en mayúsculas

Este ejemplo recupera el valor que agrega el usuario, se convierte la cadena en esa ubicación a mayúscula y se reemplaza el valor por la cadena en mayúscula:

Node.js

Usa protobufjs para decodificar los datos del evento. Incluye el google.events.cloud.firestore.v1 data.proto en la fuente.

const functions = require('@google-cloud/functions-framework');
const Firestore = require('@google-cloud/firestore');
const protobuf = require('protobufjs');

const firestore = new Firestore({
  projectId: process.env.GOOGLE_CLOUD_PROJECT,
});

// Converts strings added to /messages/{pushId}/original to uppercase
functions.cloudEvent('makeUpperCase', async cloudEvent => {
  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  const resource = firestoreReceived.value.name;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

  const curValue = firestoreReceived.value.fields.original.stringValue;
  const newValue = curValue.toUpperCase();

  if (curValue === newValue) {
    // Value is already upper-case
    // Don't perform a(nother) write to avoid infinite loops
    console.log('Value is already upper-case.');
    return;
  }

  console.log(`Replacing value: ${curValue} --> ${newValue}`);
  affectedDoc.set({
    original: newValue,
  });
});

Python

from cloudevents.http import CloudEvent
import functions_framework
from google.cloud import firestore
from google.events.cloud import firestore as firestoredata

client = firestore.Client()


# Converts strings added to /messages/{pushId}/original to uppercase
@functions_framework.cloud_event
def make_upper_case(cloud_event: CloudEvent) -> None:
    firestore_payload = firestoredata.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    path_parts = firestore_payload.value.name.split("/")
    separator_idx = path_parts.index("documents")
    collection_path = path_parts[separator_idx + 1]
    document_path = "/".join(path_parts[(separator_idx + 2) :])

    print(f"Collection path: {collection_path}")
    print(f"Document path: {document_path}")

    affected_doc = client.collection(collection_path).document(document_path)

    cur_value = firestore_payload.value.fields["original"].string_value
    new_value = cur_value.upper()

    if cur_value != new_value:
        print(f"Replacing value: {cur_value} --> {new_value}")
        affected_doc.set({"original": new_value})
    else:
        # Value is already upper-case
        # Don't perform a second write (which can trigger an infinite loop)
        print("Value is already upper-case.")

Go


// Package upper contains a Firestore Cloud Function.
package upper

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"strings"

	"cloud.google.com/go/firestore"
	firebase "firebase.google.com/go/v4"
	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

// set the GOOGLE_CLOUD_PROJECT environment variable when deploying.
var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")

// client is a Firestore client, reused between function invocations.
var client *firestore.Client

func init() {
	// Use the application default credentials.
	conf := &firebase.Config{ProjectID: projectID}

	// Use context.Background() because the app/client should persist across
	// invocations.
	ctx := context.Background()

	app, err := firebase.NewApp(ctx, conf)
	if err != nil {
		log.Fatalf("firebase.NewApp: %v", err)
	}

	client, err = app.Firestore(ctx)
	if err != nil {
		log.Fatalf("app.Firestore: %v", err)
	}

	// Register cloud event function
	functions.CloudEvent("MakeUpperCase", MakeUpperCase)
}

// MakeUpperCase is triggered by a change to a Firestore document. It updates
// the `original` value of the document to upper case.
func MakeUpperCase(ctx context.Context, e event.Event) error {
	var data firestoredata.DocumentEventData

	// If you omit `DiscardUnknown`, protojson.Unmarshal returns an error
	// when encountering a new or unknown field.
	options := proto.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err := options.Unmarshal(e.Data(), &data)

	if err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	if data.GetValue() == nil {
		return errors.New("Invalid message: 'Value' not present")
	}

	fullPath := strings.Split(data.GetValue().GetName(), "/documents/")[1]
	pathParts := strings.Split(fullPath, "/")
	collection := pathParts[0]
	doc := strings.Join(pathParts[1:], "/")

	var originalStringValue string
	if v, ok := data.GetValue().GetFields()["original"]; ok {
		originalStringValue = v.GetStringValue()
	} else {
		return errors.New("Document did not contain field \"original\"")
	}

	newValue := strings.ToUpper(originalStringValue)
	if originalStringValue == newValue {
		log.Printf("%q is already upper case: skipping", originalStringValue)
		return nil
	}
	log.Printf("Replacing value: %q -> %q", originalStringValue, newValue)

	newDocumentEntry := map[string]string{"original": newValue}
	_, err = client.Collection(collection).Doc(doc).Set(ctx, newDocumentEntry)
	if err != nil {
		return fmt.Errorf("Set: %w", err)
	}
	return nil
}

Java

import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.SetOptions;
import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.events.cloud.firestore.v1.Value;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

public class FirebaseFirestoreReactive implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestoreReactive.class.getName());
  private final Firestore firestore;

  private static final String FIELD_KEY = "original";
  private static final String APPLICATION_PROTOBUF = "application/protobuf";

  public FirebaseFirestoreReactive() {
    this(FirestoreOptions.getDefaultInstance().getService());
  }

  public FirebaseFirestoreReactive(Firestore firestore) {
    this.firestore = firestore;
  }

  @Override
  public void accept(CloudEvent event)
      throws InvalidProtocolBufferException, InterruptedException, ExecutionException {
    if (event.getData() == null) {
      logger.warning("No data found in event!");
      return;
    }

    if (!event.getDataContentType().equals(APPLICATION_PROTOBUF)) {
      logger.warning(String.format("Found unexpected content type %s, expected %s",
          event.getDataContentType(),
          APPLICATION_PROTOBUF));
      return;
    }

    DocumentEventData firestoreEventData = DocumentEventData
        .parseFrom(event.getData().toBytes());

    // Get the fields from the post-operation document snapshot
    // https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents#Document
    Map<String, Value> fields = firestoreEventData.getValue().getFieldsMap();
    if (!fields.containsKey(FIELD_KEY)) {
      logger.warning("Document does not contain original field");
      return;
    }
    String currValue = fields.get(FIELD_KEY).getStringValue();
    String newValue = currValue.toUpperCase();

    if (currValue.equals(newValue)) {
      logger.info("Value is already upper-case");
      return;
    }

    // Retrieve the document name from the resource path:
    // projects/{project_id}/databases/{database_id}/documents/{document_path}
    String affectedDoc = firestoreEventData.getValue()
        .getName()
        .split("/documents/")[1]
        .replace("\"", "");

    logger.info(String.format("Replacing values: %s --> %s", currValue, newValue));

    // Wait for the async call to complete
    this.firestore
        .document(affectedDoc)
        .set(Map.of(FIELD_KEY, newValue), SetOptions.merge())
        .get();
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Firestore;
using Google.Cloud.Functions.Framework;
using Google.Cloud.Functions.Hosting;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace FirestoreReactive;

public class Startup : FunctionsStartup
{
    public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) =>
        services.AddSingleton(FirestoreDb.Create());
}

// Register the startup class to provide the Firestore dependency.
[FunctionsStartup(typeof(Startup))]
public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;
    private readonly FirestoreDb _firestoreDb;

    public Function(ILogger<Function> logger, FirestoreDb firestoreDb) =>
        (_logger, _firestoreDb) = (logger, firestoreDb);

    public async Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        // Get the recently-written value. This expression will result in a null value
        // if any of the following is true:
        // - The event doesn't contain a "new" document
        // - The value doesn't contain a field called "original"
        // - The "original" field isn't a string
        string currentValue = data.Value?.ConvertFields().GetValueOrDefault("original") as string;
        if (currentValue is null)
        {
            _logger.LogWarning($"Event did not contain a suitable document");
            return;
        }

        string newValue = currentValue.ToUpperInvariant();
        if (newValue == currentValue)
        {
            _logger.LogInformation("Value is already upper-cased; no replacement necessary");
            return;
        }

        // The CloudEvent subject is "documents/x/y/...".
        // The Firestore SDK FirestoreDb.Document method expects a reference relative to
        // "documents" (so just the "x/y/..." part). This may be simplified over time.
        if (cloudEvent.Subject is null || !cloudEvent.Subject.StartsWith("documents/"))
        {
            _logger.LogWarning("CloudEvent subject is not a document reference.");
            return;
        }
        string documentPath = cloudEvent.Subject.Substring("documents/".Length);

        _logger.LogInformation("Replacing '{current}' with '{new}' in '{path}'", currentValue, newValue, documentPath);
        await _firestoreDb.Document(documentPath).UpdateAsync("original", newValue, cancellationToken: cancellationToken);
    }
}

Implementa la función Convertir en mayúsculas

  1. Si aún no está lista, configura la base de datos de Firestore.

  2. Usa el siguiente comando para implementar una función que se activa a través de eventos de escritura en el documento companies/{CompanyId}:

    gcloud functions deploy FUNCTION_NAME \
    --gen2 \
    --runtime=RUNTIME \
    --trigger-location=TRIGGER REGION \
    --region=REGION \
    --source=. \
    --entry-point=ENTRY_POINT \
    --set-env-vars GOOGLE_CLOUD_PROJECT=PROJECT_ID \
    --trigger-event-filters=type=google.cloud.firestore.document.v1.written \
    --trigger-event-filters=database='(default)' \
    --trigger-event-filters-path-pattern=document='messages/{pushId}'

    Reemplaza lo siguiente:

    • FUNCTION_NAME: un nombre para la función implementada.
    • RUNTIME: el entorno de ejecución de lenguaje que usa tu función.
    • REGION: la región en la que se implementará la función.
    • TRIGGER_REGION: La ubicación del activador, que debe ser la misma que la región de la base de datos de Firestore.
    • ENTRY_POINT: el punto de entrada a tu función en tu código fuente. Este es el código que se ejecuta cuando se ejecuta tu función.
    • PROJECT_ID: Es el identificador único del proyecto.

    Usa los otros campos tal como están:

    • --trigger-event-filters=type=google.cloud.firestore.document.v1.written especifica que la función se activa cuando se crea, actualiza o borra un documento, según el tipo de evento google.cloud.firestore.document.v1.written.
    • --trigger-event-filters=database='(default)' especifica la base de datos de Firestore. Para ver el nombre de la base de datos predeterminada, usa (default).
    • --trigger-event-filters-path-pattern=document='messages/{pushId}' proporciona el patrón de ruta de acceso de los documentos que deben supervisarse para detectar cambios relevantes. En este patrón de ruta de acceso, se indica que se deben supervisar todos los documentos de la colección messages. Para obtener más información, consulta Información sobre los patrones de ruta de acceso.

Prueba la función Convertir en mayúsculas

Para probar la función Convertir en mayúsculas que acabas de implementar, configura una colección llamada messages en la base de datos de Firestore:

  1. Ir a la página de Datos de Firestore.

  2. Haz clic en Iniciar una colección.

  3. Especifica messages como el ID de colección.

  4. Para empezar a agregar el primer documento de la colección, en Agregar su primer documento, acepta el ID de documento generado de forma automática.

  5. Para activar la función implementada, agrega un documento en el que el nombre del campo sea “original” y el valor del campo sea una palabra en minúscula, por ejemplo:

    Captura de pantalla que muestra cómo crear una colección de Firestore

  6. Cuando guardes el documento, verás la palabra en minúsculas en el campo de valor que convierte a mayúsculas.

    Si luego editas el valor del campo para que contenga letras minúsculas, se activará la función de nuevo y se convertirán todas las letras minúsculas en mayúsculas.

Limitaciones

  • No se garantiza el ordenamiento. Los cambios rápidos pueden activar invocaciones de funciones en un orden inesperado.
  • Los eventos se entregan al menos una vez, pero un solo evento puede dar lugar a varias invocaciones de funciones. Evita depender de la mecánica de entrega de eventos exactamente una vez y escribe funciones idempotentes.
  • Un activador se asocia con una sola base de datos. No puedes crear un activador que coincida con varias bases de datos.
  • Cuando se borra una base de datos, no se borra automáticamente ningún activador de la base de datos. El activador deja de entregar eventos, pero sigue existiendo hasta que lo borras.