Pemicu Firebase Realtime Database

Dengan fungsi Cloud Run, Anda dapat menangani peristiwa di Firebase Realtime Database dalam project Google Cloud yang sama dengan fungsinya. Dengan fungsi Cloud Run, Anda dapat menjalankan operasi {i>database<i} dengan hak istimewa administratif penuh, dan memastikan bahwa perubahan ke {i>database<i} diproses secara individual. Anda dapat membuat perubahan pada Firebase Realtime Database melalui Firebase Admin SDK.

Dalam siklus proses umum, fungsi Firebase Realtime Database melakukan hal-hal berikut:

  1. Menunggu perubahan pada lokasi database tertentu.

  2. Terpicu ketika suatu peristiwa terjadi dan menjalankan tugasnya.

  3. Menerima objek data yang berisi snapshot data yang disimpan dalam dokumen yang ditentukan.

Jenis peristiwa

Fungsi memungkinkan Anda menangani peristiwa database pada dua tingkat kekhususan; Anda dapat hanya memantau peristiwa pembuatan, pembaruan, atau penghapusan, atau Anda dapat memantau perubahan apa pun pada jalur. Fungsi Cloud Run mendukung jenis peristiwa berikut untuk Realtime Database:

Jenis Peristiwa Pemicu
providers/google.firebase.database/eventTypes/ref.write Dipicu saat peristiwa mutasi: saat data dibuat, diperbarui, atau dihapus di Realtime Database.
providers/google.firebase.database/eventTypes/ref.create (default) Dipicu saat data baru dibuat di Realtime Database.
providers/google.firebase.database/eventTypes/ref.update Dipicu saat data diperbarui di Realtime Database.
providers/google.firebase.database/eventTypes/ref.delete Dipicu saat data dihapus dari Realtime Database.

Menentukan instance dan jalur database

Untuk mengontrol kapan dan di mana fungsi Anda terpicu, Anda perlu menentukan jalur, dan secara opsional menentukan instance database.

Jalur

Spesifikasi jalur cocok dengan semua penulisan yang menyentuh suatu jalur, termasuk penulisan yang terjadi di bawahnya. Jika Anda menetapkan /foo/bar sebagai jalur fungsi, jalur tersebut akan cocok dengan peristiwa di kedua lokasi ini:

 /foo/bar
 /foo/bar/baz/really/deep/path

Bagaimanapun juga, Firebase akan menafsirkan bahwa peristiwa terjadi di /foo/bar, dan data peristiwa menyertakan data lama dan baru di /foo/bar. Jika data peristiwa kemungkinan berukuran besar, sebaiknya gunakan beberapa fungsi di jalur yang lebih dalam, bukan fungsi tunggal di dekat root database Anda. Untuk mendapatkan performa terbaik, hanya minta data di level sedalam mungkin.

Anda dapat menentukan komponen jalur sebagai karakter pengganti dengan mengapitnya menggunakan tanda kurung kurawal; foo/{bar} cocok dengan turunan apa pun dari /foo. Nilai komponen jalur karakter pengganti ini tersedia dalam objek event.params di fungsi Anda. Dalam contoh ini, nilainya tersedia sebagai event.params.bar.

Jalur dengan karakter pengganti dapat cocok dengan beberapa peristiwa dari satu penulisan. Sisipan:

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

cocok dengan jalur /foo/{bar} dua kali: sekali dengan "hello": "world" dan sekali lagi dengan "firebase": "functions".

Instance

Saat menggunakan Konsol Google Cloud, instance database harus ditentukan.

Saat menggunakan Google Cloud CLI, instance harus ditentukan sebagai bagian dari string --trigger-resource.

Misalnya, string berikut akan menggunakan string berikut dalam string --trigger-resource Anda:

--trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/PATH

Struktur peristiwa

Saat menangani peristiwa Realtime Database, objek data berisi dua properti yang disediakan dalam format objek JSON:

  • data: snapshot data yang diambil sebelum peristiwa yang memicu fungsi.

  • delta: snapshot data yang diambil setelah peristiwa yang memicu fungsi.

Contoh kode

Node.js

/**
 * Background Function triggered by a change to a Firebase RTDB reference.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Object} context The Cloud Functions event context.
 */
exports.helloRTDB = (event, context) => {
  const triggerResource = context.resource;

  console.log(`Function triggered by change to: ${triggerResource}`);
  console.log(`Admin?: ${!!context.auth.admin}`);
  console.log('Delta:');
  console.log(JSON.stringify(event.delta, null, 2));
};

Python

import json

def hello_rtdb(data, context):
    """Triggered by a change to a Firebase RTDB reference.
    Args:
        data (dict): The event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """
    trigger_resource = context.resource

    print("Function triggered by change to: %s" % trigger_resource)
    print("Admin?: %s" % data.get("admin", False))
    print("Delta:")
    print(json.dumps(data["delta"]))

Go


// Package p contains a Cloud Function triggered by a Firebase Realtime Database
// event.
package p

import (
	"context"
	"fmt"
	"log"

	"cloud.google.com/go/functions/metadata"
)

// RTDBEvent is the payload of a RTDB event.
type RTDBEvent struct {
	Data  interface{} `json:"data"`
	Delta interface{} `json:"delta"`
}

// HelloRTDB handles changes to a Firebase RTDB.
func HelloRTDB(ctx context.Context, e RTDBEvent) error {
	meta, err := metadata.FromContext(ctx)
	if err != nil {
		return fmt.Errorf("metadata.FromContext: %w", err)
	}
	log.Printf("Function triggered by change to: %v", meta.Resource)
	log.Printf("%+v", e)
	return nil
}

Java

import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.logging.Logger;

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

  // Use GSON (https://github.com/google/gson) to parse JSON content.
  private static final Gson gson = new Gson();

  @Override
  public void accept(String json, Context context) {
    logger.info("Function triggered by change to: " + context.resource());

    JsonObject body = gson.fromJson(json, JsonObject.class);

    boolean isAdmin = false;
    if (body != null && body.has("auth")) {
      JsonObject authObj = body.getAsJsonObject("auth");
      isAdmin = authObj.has("admin") && authObj.get("admin").getAsBoolean();
    }

    logger.info("Admin?: " + isAdmin);

    if (body != null && body.has("delta")) {
      logger.info("Delta:");
      logger.info(body.get("delta").toString());
    }
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Firebase.Database.V1;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseRtdb;

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

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

    public Task HandleAsync(CloudEvent cloudEvent, ReferenceEventData data, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Function triggered by change to {subject}", cloudEvent.Subject);
        _logger.LogInformation("Delta: {delta}", data.Delta);

        // 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;
    }
}

Ruby

require "functions_framework"

# Triggered by a change to a Firebase RTDB document.
FunctionsFramework.cloud_event "hello_rtdb" do |event|
  # Event-triggered Ruby functions receive a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  # The Firebase event payload can be obtained from the `data` field.
  payload = event.data

  logger.info "Function triggered by change to: #{event.source}"
  logger.info "Admin?: #{payload.fetch 'admin', false}"
  logger.info "Delta: #{payload['delta']}"
end

PHP


use Google\CloudFunctions\CloudEvent;

function firebaseRTDB(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');

    fwrite($log, 'Event: ' . $cloudevent->getId() . PHP_EOL);

    $data = $cloudevent->getData();
    $resource = $data['resource'] ?? '<null>';

    fwrite($log, 'Function triggered by change to: ' . $resource . PHP_EOL);

    $isAdmin = isset($data['auth']['admin']) && $data['auth']['admin'] == true;

    fwrite($log, 'Admin?: ' . var_export($isAdmin, true) . PHP_EOL);
    fwrite($log, 'Delta: ' . json_encode($data['delta'] ?? '') . PHP_EOL);
}

Men-deploy fungsi Anda

Perintah gclo d berikut men-deploy fungsi yang akan dipicu oleh peristiwa create di jalur /messages/{pushId}/original:

gcloud functions deploy FUNCTION_NAME \
  --entry-point ENTRY_POINT \
  --trigger-event providers/google.firebase.database/eventTypes/ref.create \
  --trigger-resource projects/_/instances/DATABASE_INSTANCE/refs/messages/{pushId}/original \
  --runtime RUNTIME
Argumen Deskripsi
FUNCTION_NAME Nama terdaftar fungsi Cloud Run yang Anda deploy. Ini dapat berupa nama fungsi dalam kode sumber Anda, atau string arbitrer. Jika FUNCTION_NAME adalah string arbitrer, Anda harus menyertakan flag --entry-point.
--entry-point ENTRY_POINT Nama fungsi atau class dalam kode sumber Anda. Opsional, kecuali jika Anda tidak menggunakan FUNCTION_NAME untuk menentukan fungsi dalam kode sumber yang akan dijalankan selama deployment. Dalam hal ini, Anda harus menggunakan --entry-point untuk memberikan nama fungsi yang dapat dieksekusi.
--trigger-event NAME Nama jenis peristiwa yang ingin diterima fungsi. Dalam hal ini, isinya adalah salah satu dari berikut ini: menulis, membuat, memperbarui, atau menghapus.
--trigger-resource NAME Lokasi database yang sepenuhnya memenuhi syarat yang akan dipantau oleh fungsi. Format ini harus sesuai dengan format berikut: projects/_/instances/DATABASE_INSTANCE/refs/PATH.
--runtime RUNTIME Nama runtime yang Anda gunakan. Untuk daftar lengkapnya, lihat referensi gcloud.