باستخدام Cloud Functions، يمكنك التعامل مع الأحداث في Firebase Realtime Database بدون الحاجة إلى تعديل رمز العميل. تتيح لك Cloud Functions تنفيذ عمليات Realtime Database مع امتيازات إدارية كاملة، وتضمن معالجة كل تغيير في Realtime Database بشكل فردي. يمكنك إجراء Firebase Realtime Database تغييرات من خلال لقطة البيانات أو من خلال "SDK للمشرف".
في دورة حياة نموذجية، تنفّذ الدالة Firebase Realtime Database ما يلي:
- تنتظر هذه السمة حدوث تغييرات في مسار Realtime Database معيّن.
- يتم تشغيل هذا التطبيق عند وقوع حدث وينفّذ مهامه.
- يتلقّى عنصر بيانات يحتوي على لقطة من البيانات المخزّنة في هذا المسار.
يمكنك تشغيل دالة استجابةً لكتابة أو إنشاء أو تعديل أو حذف عُقد قاعدة بيانات في Firebase Realtime Database. للتحكّم في وقت تشغيل الدالة، حدِّد أحد معالِجات الأحداث، ثم حدِّد مسار Realtime Database الذي سيتم الاستماع فيه إلى الأحداث.
ضبط موقع الدالة
يمكن أن تؤدي المسافة بين موقع مثيل Realtime Database وموقع الدالة إلى حدوث تأخير كبير في الشبكة. بالإضافة إلى ذلك، يمكن أن يؤدي عدم التطابق بين المناطق إلى تعذُّر النشر. لتجنُّب هذه الحالات، حدِّد موقع الدالة ليتطابق مع موقع مثيل قاعدة البيانات.
التعامل مع أحداث Realtime Database
تتيح لك الدوال التعامل مع أحداث Realtime Database بمستويين من التحديد؛ يمكنك الاستماع إلى أحداث الكتابة أو الإنشاء أو التعديل أو الحذف فقط، أو يمكنك الاستماع إلى أي تغيير من أي نوع في مرجع.
تتوفّر معالِجات الردّ على أحداث Realtime Database التالية:
Node.js
onValueWritten()
يتم تشغيل هذا الإجراء عند إنشاء البيانات أو تعديلها أو حذفها في Realtime Database.onValueCreated()
يتم تفعيلها فقط عند إنشاء البيانات في Realtime Database.onValueUpdated()
يتم تشغيله فقط عند تعديل البيانات في Realtime Database.onValueDeleted()
يتم تفعيلها فقط عند حذف البيانات في Realtime Database.
Python
on_value_written()
يتم تشغيل هذا الإجراء عند إنشاء البيانات أو تعديلها أو حذفها في Realtime Database.on_value_created()
يتم تفعيلها فقط عند إنشاء البيانات في Realtime Database.on_value_updated()
يتم تشغيله فقط عند تعديل البيانات في Realtime Database.on_value_deleted()
يتم تفعيلها فقط عند حذف البيانات في Realtime Database.
استيراد الوحدات المطلوبة
في مصدر الدالة، يجب استيراد وحدات حزمة SDK التي تريد استخدامها. بالنسبة إلى هذا المثال، من الضروري استيراد وحدتَي HTTP وRealtime Database بالإضافة إلى وحدة Firebase Admin SDK للكتابة إلى Realtime Database.
Node.js
// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onRequest} = require("firebase-functions/v2/https");
const {onValueCreated} = require("firebase-functions/v2/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()
تحديد المثيل والمسار
للتحكّم في وقت ومكان تشغيل الدالة، اضبط الدالة باستخدام مسار وRealtime Database اختياريًا. إذا لم تحدِّد مثيلاً، ستستمع الدالة إلى جميع مثيلات Realtime Database في منطقة الدالة. يمكنك أيضًا تحديد نمط مثيل Realtime Database لنشره على مجموعة فرعية انتقائية من المثيلات في المنطقة نفسها.
على سبيل المثال:
Node.js
// All Realtime Database instances in default function region us-central1 at path "/user/{uid}" // There must be at least one Realtime Database present in us-central1. 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" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (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-*" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (event) => { // … } );
Python
# All Realtime Database instances in default function region us-central1 at path "/user/{uid}"
# There must be at least one Realtime Database present in us-central1.
@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",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
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-*",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
# ...
pass
توجّه هذه المَعلمات الدالة للتعامل مع عمليات الكتابة في مسار معيّن ضمن مثيل Realtime Database.
تتطابق مواصفات المسار مع جميع عمليات الكتابة التي تتضمّن مسارًا، بما في ذلك عمليات الكتابة التي تحدث في أي مكان أدناه. إذا ضبطت المسار الخاص بالدالة على /foo/bar
، سيتم الربط بالأحداث في كلا الموقعين التاليين:
/foo/bar
/foo/bar/baz/really/deep/path
في كلتا الحالتين، تفسّر Firebase أنّ الحدث يقع في /foo/bar
،
وتتضمّن بيانات الحدث البيانات القديمة والجديدة في /foo/bar
. إذا كانت بيانات الحدث كبيرة الحجم، ننصحك باستخدام دوال متعددة في مسارات أعمق بدلاً من دالة واحدة بالقرب من جذر قاعدة البيانات. للحصول على أفضل أداء، اطلب البيانات على أدق مستوى ممكن فقط.
استخدام أحرف البدل والتقاط البيانات
يمكنك استخدام {key}
و{key=*}
و{key=prefix*}
و{key=*suffix}
للتسجيل. *
وprefix*
و*suffix
للبحث عن أحرف البدل في مقطع واحد
ملاحظة: يمثّل **
أحرف البدل المتعدّدة الأجزاء، وهو ما لا يتيحه Realtime Database.
اطّلِع على التعرّف على أنماط المسارات.
استخدام أحرف البدل في المسار: يمكنك تحديد مكوّن مسار كحرف بدل:
- استخدام علامة النجمة:
*
على سبيل المثال، يطابقfoo/*
أي عناصر فرعية بمستوى واحد من التسلسل الهرمي للعقدة أسفلfoo/
. - استخدام مقطع يحتوي على علامة نجمية بالضبط،
*
على سبيل المثال،foo/app*-us
يطابق أي مقاطع فرعية أدناهfoo/
مع البادئةapp
واللاحقة-us
.
يمكن أن تتطابق المسارات التي تتضمّن أحرف بدل مع أحداث متعددة، مثل عملية كتابة واحدة. إدراج
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
يطابق المسار "/foo/*"
مرتين: مرة واحدة مع "hello": "world"
ومرة أخرى مع "firebase": "functions"
.
تسجيل المسار: يمكنك تسجيل تطابقات المسار في متغيرات مسماة لاستخدامها في رمز الدالة (مثل /user/{uid}
و/user/{uid=*-us}
).
تتوفّر قيم متغيرات الالتقاط ضمن الكائن database.DatabaseEvent.params الخاص بالدالة.
استخدام أحرف البدل في المثيلات: يمكنك أيضًا تحديد مكوّن مثيل باستخدام أحرف البدل. يمكن أن يتضمّن حرف البدل الخاص بالمثيل بادئة أو لاحقة أو كليهما (مثل my-app-*-prod
).
أحرف البدل ومرجع الالتقاط
باستخدام Cloud Functions (الجيل الثاني) وRealtime Database، يمكن استخدام نمط عند تحديد ref
وinstance
. ستتضمّن كل واجهة مشغّل الخيارات التالية لتحديد نطاق دالة:
تحديد ref |
تحديد instance |
السلوك |
---|---|---|
أغنية منفردة (/foo/bar ) |
عدم التحديد | يتم تطبيق معالج النطاقات على جميع المثيلات في منطقة الدالة. |
أغنية منفردة (/foo/bar ) |
أغنية منفردة (‘my-new-db' ) |
معالج النطاقات إلى المثيل المحدّد في منطقة الدالة |
أغنية منفردة (/foo/bar ) |
النمط (‘inst-prefix*' ) |
يتم تطبيق معالج النطاقات على جميع المثيلات التي تتطابق مع النمط في منطقة الدالة. |
النمط (/foo/{bar} ) |
عدم التحديد | يتم تطبيق معالج النطاقات على جميع المثيلات في منطقة الدالة. |
النمط (/foo/{bar} ) |
أغنية منفردة (‘my-new-db' ) |
معالج النطاقات إلى المثيل المحدّد في منطقة الدالة |
النمط (/foo/{bar} ) |
النمط (‘inst-prefix*' ) |
يتم تطبيق معالج النطاقات على جميع المثيلات التي تتطابق مع النمط في منطقة الدالة. |
التعامل مع بيانات الأحداث
عندما يتم تشغيل حدث Realtime Database، يتم تمرير عنصر Event
إلى دالة المعالجة.
يحتوي هذا العنصر على السمة data
التي تتضمّن، بالنسبة إلى أحداث الإنشاء والحذف، لقطة للبيانات التي تم إنشاؤها أو حذفها.
في هذا المثال، تسترد الدالة البيانات الخاصة بالمسار المشار إليه، وتحوّل السلسلة في ذلك الموقع إلى أحرف كبيرة، وتكتب السلسلة المعدَّلة في قاعدة البيانات:
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)
قراءة القيمة السابقة
بالنسبة إلى أحداث write
أو update
، تكون السمة data
عبارة عن كائن Change
يحتوي على لقطتَين تمثّلان حالة البيانات قبل الحدث المشغِّل وبعده.
يحتوي الكائن Change
على السمة before
التي تتيح لك فحص البيانات التي تم حفظها في Realtime Database قبل الحدث، وعلى السمة after
التي تمثّل حالة البيانات بعد وقوع الحدث.
على سبيل المثال، يمكن استخدام السمة before
للتأكّد من أنّ الدالة تحوّل النص إلى أحرف كبيرة فقط عند إنشائه لأول مرة:
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)