Realtime Database tetikleyicileri

Cloud Functions ile Firebase Realtime Database içindeki etkinlikleri istemci kodunu güncellemenize gerek kalmadan yönetebilirsiniz. Cloud Functions, Realtime Database işlemlerini tam yönetim ayrıcalıklarıyla çalıştırmanıza olanak tanır ve Realtime Database'de yapılan her değişikliğin ayrı ayrı işlenmesini sağlar. Firebase Realtime Database değişikliklerini veri anlık görüntüsü veya Admin SDK aracılığıyla yapabilirsiniz.

Tipik bir yaşam döngüsünde, Firebase Realtime Database işlevi şunları yapar:

  1. Belirli bir Realtime Database yoldaki değişiklikleri bekler.
  2. Bir etkinlik gerçekleştiğinde tetiklenir ve görevlerini yerine getirir.
  3. Bu yolda depolanan verilerin anlık görüntüsünü içeren bir veri nesnesi alır.

Firebase Realtime Database'da veritabanı düğümlerinin yazılması, oluşturulması, güncellenmesi veya silinmesi gibi işlemlere yanıt olarak bir işlevi tetikleyebilirsiniz. İşlevin ne zaman tetikleneceğini kontrol etmek için etkinlik işleyicilerden birini ve etkinlikleri dinleyeceği Realtime Database yolunu belirtin.

İşlevin konumunu ayarlama

Bir Realtime Database örneğinin konumu ile işlevin konumu arasındaki mesafe önemli ağ gecikmesine neden olabilir. Ayrıca bölgeler arasındaki uyuşmazlıklar dağıtımın başarısız olmasına neden olabilir. Bu durumları önlemek için işlev konumunu, veritabanı örneği konumuyla eşleşecek şekilde belirtin.

Realtime Database etkinliklerini işleme

İşlevler, Realtime Database etkinlikleri iki özgüllük düzeyinde işlemenize olanak tanır: Yalnızca yazma, oluşturma, güncelleme veya silme etkinliklerini dinleyebilir ya da bir referansta yapılan herhangi bir değişikliği dinleyebilirsiniz.

Realtime Database etkinliklerine yanıt vermek için şu işleyiciler kullanılabilir:

Node.js

  • onValueWritten() Veriler Realtime Database içinde oluşturulduğunda, güncellendiğinde veya silindiğinde tetiklenir.
  • onValueCreated() Yalnızca Realtime Database içinde veri oluşturulduğunda tetiklenir.
  • onValueUpdated() Yalnızca Realtime Database içinde veriler güncellendiğinde tetiklenir.
  • onValueDeleted() Yalnızca Realtime Database'da veriler silindiğinde tetiklenir.

Python

  • on_value_written() Veriler Realtime Database içinde oluşturulduğunda, güncellendiğinde veya silindiğinde tetiklenir.
  • on_value_created() Yalnızca Realtime Database içinde veri oluşturulduğunda tetiklenir.
  • on_value_updated() Yalnızca Realtime Database içinde veriler güncellendiğinde tetiklenir.
  • on_value_deleted() Yalnızca Realtime Database'da veriler silindiğinde tetiklenir.

Gerekli modülleri içe aktarma

İşlev kaynağınızda, kullanmak istediğiniz SDK modüllerini içe aktarmanız gerekir. Bu örnekte, Realtime Database modülüne yazmak için Firebase Admin SDK modülünün yanı sıra HTTP ve Realtime Database modüllerinin de içe aktarılması gerekir.

Node.js

// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onRequest} = require("firebase-functions/https");
const {onValueCreated} = require("firebase-functions/database");
const {logger} = require("firebase-functions");

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp();

Python

# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import db_fn, https_fn

# The Firebase Admin SDK to access the Firebase Realtime Database.
from firebase_admin import initialize_app, db

app = initialize_app()

Örneği ve yolu belirtin

İşlevinizin ne zaman ve nerede tetikleneceğini kontrol etmek için işlevinizi bir yolla ve isteğe bağlı olarak bir Realtime Database örneğiyle yapılandırın. Bir örnek belirtmezseniz işlev, işlev bölgesindeki tüm Realtime Database örneklerini dinler. Aynı bölgedeki örneklerin seçili bir alt kümesine dağıtmak için bir Realtime Database örnek kalıbı da belirtebilirsiniz.

Örneğin:

Node.js

// All Realtime Database instances at path "/user/{uid}"
// There must be at least one Realtime Database present.
const onWrittenFunctionDefault = onValueWritten("/user/{uid}", (event) => {
  // …
});

// Instance named "my-app-db-2", at path "/user/{uid}".
// The "my-app-db-2" instance must exist in this region.
const OnWrittenFunctionInstance = onValueWritten(
  {
    ref: "/user/{uid}",
    instance: "my-app-db-2"
  },
  (event) => {
    // …
  }
);

// Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
// There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
const onWrittenFunctionInstance = onValueWritten(
  {
    ref: "/user/{uid=*@gmail.com}",
    instance: "my-app-db-*"
  },
  (event) => {
    // …
  }
);

Python

# All Realtime Database instances at path "/user/{uid}"
# There must be at least one Realtime Database present.
@db_fn.on_value_written(r"/user/{uid}")
def onwrittenfunctiondefault(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

# Instance named "my-app-db-2", at path "/user/{uid}".
# The "my-app-db-2" instance must exist in this region.
@db_fn.on_value_written(
    reference=r"/user/{uid}",
    instance="my-app-db-2",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

# Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
# There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
@db_fn.on_value_written(
    reference=r"/user/{uid=*@gmail.com}",
    instance="my-app-db-*",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
    # ...
    pass

Bu parametreler, işlevinizi Realtime Database örneğindeki belirli bir yolda yazma işlemlerini yönetecek şekilde yönlendirir.

Yol belirtimleri, altındaki tüm yazma işlemleri de dahil olmak üzere bir yola dokunan tüm yazma işlemleriyle eşleşir. İşlevinizin yolunu /foo/bar olarak ayarlarsanız bu iki konumdaki etkinliklerle eşleşir:

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

Her iki durumda da Firebase, etkinliğin /foo/bar tarihinde gerçekleştiğini yorumlar ve etkinlik verileri, /foo/bar tarihinde eski ve yeni verileri içerir. Etkinlik verileri büyük olabilirse veritabanınızın kökünün yakınında tek bir işlev kullanmak yerine daha derin yollarda birden fazla işlev kullanmayı düşünebilirsiniz. En iyi performans için yalnızca mümkün olan en ayrıntılı düzeyde veri isteyin.

Wildcard ve yakalama

Çekim için {key}, {key=*}, {key=prefix*}, {key=*suffix} özelliklerini kullanabilirsiniz. Tek segmentli joker karakterler için *, prefix*, *suffix. Not: **, Realtime Database tarafından desteklenmeyen çok segmentli joker karakterleri temsil eder. Yol kalıplarını anlama başlıklı makaleyi inceleyin.

Yol joker karakteri. Bir yol bileşenini joker karakter olarak belirtebilirsiniz:

  • Yıldız işareti (*) kullanma Örneğin, foo/*, foo/'nin altındaki düğüm hiyerarşisinde bir düzeyde bulunan tüm alt öğelerle eşleşir.
  • Tam olarak yıldız işareti (*) içeren bir segment kullanma. Örneğin, foo/app*-us foo/ altındaki tüm çocuk segmentlerini app öneki ve -us sonekiyle eşleştirir.

Joker karakter içeren yollar, örneğin tek bir yazma işleminden birden fazla etkinlikle eşleşebilir. Şu öğenin eklenmesi:

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

"/foo/*" yoluyla iki kez eşleşir: bir kez "hello": "world" ile, bir kez de "firebase": "functions" ile.

Yol yakalama. İşlev kodunuzda kullanılacak yol eşleşmelerini adlandırılmış değişkenlere (ör. /user/{uid}, /user/{uid=*-us}) aktarabilirsiniz.

Yakalanan değişkenlerin değerleri, işlevinizin database.DatabaseEvent.params nesnesinde kullanılabilir.

Örnek joker karakteri. Ayrıca joker karakter kullanarak bir örnek bileşeni de belirtebilirsiniz. Bir örnek joker karakteri, ön ek, son ek veya her ikisini de içerebilir (ör. my-app-*-prod).

Joker karakter ve yakalama referansı

Cloud Functions (2. nesil) ve Realtime Database ile ref ve instance belirtilirken bir desen kullanılabilir. Her tetikleyici arayüzünde bir işlevin kapsamını belirlemek için aşağıdaki seçenekler bulunur:

ref belirtme instance belirtme Davranış
Tek (/foo/bar) Belirtilmiyor İşleyiciyi, işlev bölgesindeki tüm örneklerle sınırlandırır.
Tek (/foo/bar) Tek (‘my-new-db') İşleyiciyi, işlev bölgesindeki belirli örnekle sınırlandırır.
Tek (/foo/bar) Desen (‘inst-prefix*') İşleyiciyi, işlev bölgesindeki kalıpla eşleşen tüm örneklerle sınırlandırır.
Desen (/foo/{bar}) Belirtilmiyor İşleyiciyi, işlev bölgesindeki tüm örneklerle sınırlandırır.
Desen (/foo/{bar}) Tek (‘my-new-db') İşleyiciyi, işlev bölgesindeki belirli örnekle sınırlandırır.
Desen (/foo/{bar}) Desen (‘inst-prefix*') İşleyiciyi, işlev bölgesindeki kalıpla eşleşen tüm örneklerle sınırlandırır.

Etkinlik verilerini işleme

Bir Realtime Database etkinliği tetiklendiğinde, işleyici işlevinize bir Event nesnesi iletilir. Bu nesnenin data özelliği vardır. Bu özellik, oluşturma ve silme etkinlikleri için oluşturulan veya silinen verilerin anlık görüntüsünü içerir.

Bu örnekte işlev, referans verilen yolun verilerini alır, bu konumdaki dizeyi büyük harfe dönüştürür ve değiştirilen dizeyi veritabanına yazar:

Node.js

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
// for all databases in 'us-central1'
exports.makeuppercase = onValueCreated(
    "/messages/{pushId}/original",
    (event) => {
    // Grab the current value of what was written to the Realtime Database.
      const original = event.data.val();
      logger.log("Uppercasing", event.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing
      // asynchronous tasks inside a function, such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the
      // Realtime Database returns a Promise.
      return event.data.ref.parent.child("uppercase").set(uppercase);
    },
);

Python

@db_fn.on_value_created(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[Any]) -> None:
    """Listens for new messages added to /messages/{pushId}/original and
    creates an uppercase version of the message to /messages/{pushId}/uppercase
    """

    # Grab the value that was written to the Realtime Database.
    original = event.data
    if not isinstance(original, str):
        print(f"Not a string: {event.reference}")
        return

    # Use the Admin SDK to set an "uppercase" sibling.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent = db.reference(event.reference).parent
    if parent is None:
        print("Message can't be root node.")
        return
    parent.child("uppercase").set(upper)

Önceki değeri okuma

write veya update etkinlikleri için data özelliği, tetikleyici etkinlikten önce ve sonraki veri durumunu temsil eden iki anlık görüntü içeren bir Change nesnesidir. Change nesnesinde, etkinlikten Realtime Database önce before özelliğine kaydedilenleri incelemenize olanak tanıyan bir özellik ve etkinlik gerçekleştikten sonra verilerin durumunu temsil eden bir after özelliği bulunur.

Örneğin, before özelliği, işlevin metni yalnızca ilk oluşturulduğunda büyük harfe çevirmesini sağlamak için kullanılabilir:

Node.js

  exports makeUppercase = onValueWritten("/messages/{pushId}/original", (event) => {
        // Only edit data when it is first created.
        if (event.data.before.exists()) {
          return null;
        }
        // Exit when the data is deleted.
        if (!event.data.after.exists()) {
          return null;
        }
        // Grab the current value of what was written to the Realtime Database.
        const original = event.data.after.val();
        console.log('Uppercasing', event.params.pushId, original);
        const uppercase = original.toUpperCase();
        // You must return a Promise when performing asynchronous tasks inside a Functions such as
        // writing to the Firebase Realtime Database.
        // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
        return event.data.after.ref.parent.child('uppercase').set(uppercase);
      });

Python

@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase2(event: db_fn.Event[db_fn.Change]) -> None:
    """Listens for new messages added to /messages/{pushId}/original and
    creates an uppercase version of the message to /messages/{pushId}/uppercase
    """

    # Only edit data when it is first created.
    if event.data.before is not None:
        return

    # Exit when the data is deleted.
    if event.data.after is None:
        return

    # Grab the value that was written to the Realtime Database.
    original = event.data.after
    if not hasattr(original, "upper"):
        print(f"Not a string: {event.reference}")
        return

    # Use the Admin SDK to set an "uppercase" sibling.
    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent = db.reference(event.reference).parent
    if parent is None:
        print("Message can't be root node.")
        return
    parent.child("uppercase").set(upper)

Kimlik doğrulama bağlamına erişme

RTDB Eventarc etkinlikleri tarafından tetiklenen işlevler için kimlik doğrulama bağlamı etkinlik yüküne dahil edilir:

  • authtype: Etkinliği tetikleyen asıl öğenin türü. Olası değerler şunlardır:
    • app_user: Geliştiricinin uygulamasının bir son kullanıcısı.
    • admin: Hizmet hesabı.
    • unauthenticated: Kimliği doğrulanmamış bir kullanıcı.
    • unknown: Kimlik doğrulama bilgileri kullanılamadığında varsayılan olarak kullanılır.
  • authid: Asıl kullanıcının benzersiz tanımlayıcısı.
    • authtype app_user ise bu, kullanıcının UID'sidir.
    • authtype admin ise bu, hizmet hesabı veya IAM kullanıcı e-postasıdır.

Bu kod, yalnızca işlevi tetikleyen kullanıcı yönetici değilse iletinin metnini büyük harfe dönüştürür. Ayrıca kod, iletiyi tetikleyen kullanıcının iletinin gerçek göndereni olup olmadığını da kontrol eder.

Node.js

// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onValueWritten} = require("firebase-functions/v2/database");
const {logger} = require("firebase-functions");
const admin = require("firebase-admin");

admin.initializeApp();

exports.dbtrigger = onValueWritten("/messages/{pushId}/original", async (event) => {
  // 1. Check whether authtype is admin. If it is, skip this operation.
  if (event.authType === "admin") {
    logger.log("Modification by admin detected. Skipping uppercase conversion.");
    return null;
  }

  // 2. Retrieve the userID of the sender (assumed sibling node 'senderId')
  const snapshot = await event.data.after.ref.parent.child("senderId").get();
  const senderId = snapshot.val();

  // 3. Check if userID of sender of message = event.authid
  if (senderId !== event.authId) {
    logger.error(`Unauthorized write: senderId (${senderId}) does not match authId (${event.authId})`);
    return null;
  }

  // Grab the value that was written to the Realtime Database.
  const original = event.data.after.val();
  logger.log("Uppercasing", event.params.pushId, original);
  const uppercase = original.toUpperCase();

  // Return the promise to set the "uppercase" sibling node.
  return event.data.after.ref.parent.child("uppercase").set(uppercase);
});

Python

from firebase_functions import db_fn
from firebase_admin import initialize_app, db

initialize_app()

@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[db_fn.Change]) -> None:
    # 1. Check whether authtype is admin. If it is, skip this operation.
    if event.auth_type == "admin":
        print("Admin user detected. Skipping.")
        return

    # 2. Retrieve the userID of the sender (assumed sibling node: 'senderId')
    parent_ref = db.reference(event.reference).parent
    sender_id = parent_ref.child("senderId").get()

    # 3. Check if userID of sender = event.auth_id
    if sender_id != event.auth_id:
        print(f"Unauthorized: sender_id {sender_id} != auth_id {event.auth_id}")
        return

    # Exit when the data is deleted.
    if event.data.after is None:
        return

    # Grab the value and uppercase it
    original = event.data.after
    if not isinstance(original, str):
        return

    print(f"Uppercasing {event.params['pushId']}: {original}")
    upper = original.upper()
    parent_ref.child("uppercase").set(upper)