استرداد البيانات باستخدام قاعدة بيانات Firebase في الوقت الفعلي للغة C++

يتناول هذا المستند أساسيات استرداد البيانات وكيفية ترتيب بيانات Firebase وفلترتها.

قبل البدء

تأكَّد من إعداد تطبيقك وإمكانية الوصول إلى قاعدة البيانات كما هو موضّح في دليل Get Started.

جارٍ استرداد البيانات

يتم استرداد بيانات Firebase إما من خلال طلب لمرة واحدة إلى GetValue() أو إرفاقها بـ ValueListener في مرجع FirebaseDatabase. يتم استدعاء مستمع القيمة مرة واحدة للحالة الأولية للبيانات ومرة أخرى في أي وقت تتغير فيه البيانات.

الحصول على DatabaseReference

لكتابة البيانات في قاعدة البيانات، تحتاج إلى مثيل من DatabaseReference:

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

قراءة البيانات لمرة واحدة

يمكنك استخدام طريقة GetValue() لقراءة لقطة ثابتة للمحتوى في مسار معيّن مرة واحدة. ستحتوي نتيجة المهمة على لقطة تحتوي على جميع البيانات في ذلك الموقع، بما في ذلك البيانات الفرعية. إذا لم تكن هناك بيانات، ستكون اللقطة المعروضة هي null.

  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").GetValue();

في هذه المرحلة، تم إرسال الطلب ولكن علينا انتظار اكتمال Future قبل أن نتمكن من قراءة القيمة. بما أنّ الألعاب تعمل عادةً في حلقة تكرار، وتعتمد على عمليات الاستدعاء بشكل أقل من التطبيقات الأخرى، ستستعلم عادةً عن اكتمال العملية.

  // In the game loop that polls for the result...

  if (result.status() != firebase::kFutureStatusPending) {
    if (result.status() != firebase::kFutureStatusComplete) {
      LogMessage("ERROR: GetValue() returned an invalid result.");
      // Handle the error...
    } else if (result.error() != firebase::database::kErrorNone) {
      LogMessage("ERROR: GetValue() returned error %d: %s", result.error(),
                 result.error_message());
      // Handle the error...
    } else {
      firebase::database::DataSnapshot snapshot = result.result();
      // Do something with the snapshot...
    }
  }

يعرض هذا المثال بعض عمليات التحقّق الأساسية من الأخطاء. يمكنك الاطّلاع على مرجع firebase::Future لمزيد من المعلومات حول التحقّق من الأخطاء وطرق تحديد وقت جاهزية النتيجة.

الاستماع إلى الأحداث

يمكنك إضافة مستمعين للاشتراك في التغييرات التي تطرأ على البيانات:

صنف أساسي واحد (ValueListener)

رد الاتصال الاستخدام المعتاد
OnValueChanged قراءة التغييرات التي تطرأ على محتوى مسار بالكامل والاستماع إليها

صنف أساسي واحد (OnChildListener)

OnChildAdded استرداد قوائم العناصر أو الاستماع إلى الإضافات إلى قائمة العناصر يُقترح استخدامها مع OnChildChanged وOnChildRemoved لمراقبة التغييرات في القوائم.
OnChildChanged الاستماع إلى التغييرات التي تطرأ على العناصر في قائمة يمكنك استخدامها مع OnChildAdded وOnChildRemoved لمراقبة التغييرات في القوائم.
OnChildRemoved الاستماع إلى العناصر التي تتم إزالتها من القائمة يمكنك استخدامها مع OnChildAdded وOnChildChanged لمراقبة التغييرات في القوائم.
OnChildMoved الاستماع إلى التغييرات في ترتيب العناصر في قائمة مع ترتيب يتم دائمًا تنفيذ عمليات الاستدعاء OnChildMoved بعد عمليات الاستدعاء OnChildChanged بسبب تغيير ترتيب العنصر (استنادًا إلى طريقة الترتيب الحالية).

فئة ValueListener

يمكنك استخدام عمليات الاستدعاء OnValueChanged للاشتراك في التغييرات التي تطرأ على المحتوى في مسار معيّن. يتم تشغيل رد الاتصال هذا مرة واحدة عند إرفاق المستمع ومرة أخرى في كل مرة تتغير فيها البيانات، بما في ذلك العناصر الفرعية. يتم تمرير لقطة تحتوي على جميع البيانات في ذلك الموقع الجغرافي، بما في ذلك بيانات العناصر الثانوية، إلى دالة الاستدعاء. إذا لم تكن هناك بيانات، تكون اللقطة المعروضة هي null.

يوضّح المثال التالي كيفية استرداد لعبة لنتائج قائمة الصدارة من قاعدة البيانات:

  class LeadersValueListener : public firebase::database::ValueListener {
   public:
    void OnValueChanged(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: LeadersValueListener canceled: %d: %s", error_code,
                 error_message);
    }
  };

  // Elsewhere in the code...

  LeadersValueListener* listener = new LeadersValueListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

تحتوي النتيجة Future&ltDataSnapshot&gt على البيانات في الموقع المحدّد في قاعدة البيانات في وقت الحدث. يؤدي استدعاء value() في لقطة إلى عرض Variant يمثّل البيانات.

في هذا المثال، يتم أيضًا إلغاء طريقة OnCancelled لمعرفة ما إذا تم إلغاء القراءة. على سبيل المثال، يمكن إلغاء عملية قراءة إذا لم يكن لدى العميل إذن بالقراءة من موقع قاعدة بيانات Firebase. ستشير السمة database::Error إلى سبب حدوث الخطأ.

فئة ChildListener

يتم تشغيل الأحداث الفرعية استجابةً لعمليات محدّدة تحدث للعناصر الفرعية لعقدة من عملية مثل عنصر فرعي جديد تمت إضافته من خلال طريقة PushChild() أو عنصر فرعي يتم تعديله من خلال طريقة UpdateChildren(). يمكن أن يكون كلّ من هذه العناصر مفيدًا للاستماع إلى التغييرات في عقدة معيّنة في قاعدة البيانات. على سبيل المثال، قد تستخدم إحدى الألعاب هذه الطرق معًا لمراقبة النشاط في تعليقات جلسة اللعبة، كما هو موضّح أدناه:

  class SessionCommentsChildListener : public firebase::database::ChildListener {
   public:
    void OnChildAdded(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildChanged(const firebase::database::DataSnapshot& snapshot,
                        const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildRemoved(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot ...
    }
    void OnChildMoved(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: SessionCommentsChildListener canceled: %d: %s",
                 error_code, error_message);
    }
  };

  // elsewhere ....

  SessionCommentsChildListener* listener = new SessionCommentsChildListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

يتم استخدام دالة الاستدعاء OnChildAdded عادةً لاسترداد قائمة بالعناصر في قاعدة بيانات Firebase. يتم استدعاء دالة الاستدعاء OnChildAdded مرة واحدة لكل عنصر فرعي حالي، ثم مرة أخرى في كل مرة تتم فيها إضافة عنصر فرعي جديد إلى المسار المحدد. يتم تمرير لقطة تحتوي على بيانات العنصر الثانوي الجديد إلى المستمع.

يتم استدعاء دالة الاستدعاء OnChildChanged في أي وقت يتم فيه تعديل عقدة فرعية. ويشمل ذلك أي تعديلات على العناصر التابعة للعقدة الفرعية. ويتم استخدامها عادةً مع طلبات OnChildAdded وOnChildRemoved للاستجابة للتغييرات في قائمة العناصر. تحتوي اللقطة التي تم تمريرها إلى المستمع على البيانات المحدّثة للعنصر الفرعي.

يتم تشغيل دالة الاستدعاء OnChildRemoved عند إزالة عنصر فرعي مباشر. ويتم استخدامها عادةً مع عمليات الاستدعاء OnChildAdded وOnChildChanged. تحتوي اللقطة التي تم تمريرها إلى دالة الاستدعاء على بيانات الطفل الذي تمت إزالته.

يتم تشغيل دالة ردّ الاتصال OnChildMoved عندما يتم رفع طلب OnChildChanged من خلال تحديث يؤدي إلى إعادة ترتيب العنصر الفرعي. ويتم استخدامها مع البيانات التي يتم ترتيبها باستخدام OrderByChild أو OrderByValue.

فرز البيانات وتصفيتها

يمكنك استخدام الفئة Realtime Database Query لاسترداد البيانات التي تم ترتيبها حسب المفتاح أو القيمة أو قيمة عنصر ثانوي. يمكنك أيضًا فلترة النتيجة التي تم ترتيبها إلى عدد معيّن من النتائج أو نطاق من المفاتيح أو القيم.

ترتيب البيانات

لاسترداد البيانات التي تم ترتيبها، ابدأ بتحديد إحدى طرق الترتيب لتحديد كيفية ترتيب النتائج:

الطريقة الاستخدام
OrderByChild() ترتيب النتائج حسب قيمة مفتاح فرعي محدّد
OrderByKey() ترتيب النتائج حسب المفاتيح الفرعية
OrderByValue() ترتيب النتائج حسب القيم الفرعية

يمكنك استخدام طريقة ترتيب واحدة فقط في كل مرة. يؤدي استدعاء طريقة الترتيب عدة مرات في طلب البحث نفسه إلى ظهور خطأ.

يوضّح المثال التالي كيفية الاشتراك في قائمة صدارة مرتّبة حسب النتيجة.

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score");

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

يحدّد هذا الإجراء firebase::Query، وعند دمجه مع ValueListener، تتم مزامنة العميل مع قائمة الصدارة في قاعدة البيانات، ويتم ترتيبها حسب نتيجة كل إدخال. يمكنك الاطّلاع على مزيد من المعلومات حول تنظيم بياناتك بكفاءة في مقالة تنظيم قاعدة بياناتك.

The call to the OrderByChild() method specifies the child key to order the results by. في هذه الحالة، يتم ترتيب النتائج حسب قيمة "score" في كل عنصر فرعي. لمزيد من المعلومات حول كيفية ترتيب أنواع البيانات الأخرى، يُرجى الاطّلاع على كيفية ترتيب بيانات طلبات البحث.

تصفية البيانات

لفلترة البيانات، يمكنك دمج أي من طرق الحد أو النطاق مع طريقة الترتيب عند إنشاء طلب بحث.

الطريقة الاستخدام
LimitToFirst() تحدّد هذه المَعلمة الحد الأقصى لعدد العناصر التي سيتم عرضها من بداية قائمة النتائج المرتبة.
LimitToLast() تحدّد هذه المَعلمة الحد الأقصى لعدد العناصر التي يتم عرضها من نهاية قائمة النتائج المرتبة.
StartAt() عرض العناصر التي تزيد قيمتها عن أو تساوي المفتاح أو القيمة المحدّدة استنادًا إلى طريقة الترتيب التي تم اختيارها
EndAt() عرض العناصر التي تكون أقل من أو تساوي المفتاح أو القيمة المحدّدة حسب طريقة الترتيب التي تم اختيارها
EqualTo() عرض العناصر التي تساوي المفتاح أو القيمة المحدّدة حسب طريقة الترتيب التي تم اختيارها

على عكس طرق الترتيب، يمكنك الجمع بين عدة دوال للحدّ أو النطاق. على سبيل المثال، يمكنك الجمع بين الطريقتين StartAt() وEndAt() لحصر النتائج في نطاق محدّد من القيم.

حتى في حال توفُّر مطابقة واحدة فقط لطلب البحث، تظل اللقطة قائمة، ولكنّها تحتوي على عنصر واحد فقط.

تحديد عدد النتائج

يمكنك استخدام الطريقتَين LimitToFirst() وLimitToLast() لضبط الحد الأقصى لعدد العناصر الفرعية التي تتم مزامنتها لردّ اتصال معيّن. على سبيل المثال، إذا كنت تستخدم LimitToFirst() لضبط حدّ أقصى يبلغ 100، لن تتلقّى في البداية سوى ما يصل إلى 100 طلب معاودة اتصال من OnChildAdded. إذا كان لديك أقل من 100 عنصر مخزّن في قاعدة بيانات Firebase، يتم تنشيط دالة رد اتصال OnChildAdded لكل عنصر.

عندما تتغيّر العناصر، ستتلقّى عمليات استدعاء OnChildAdded للعناصر التي تدخل في طلب البحث وعمليات استدعاء OnChildRemoved للعناصر التي تخرج منه، ليبقى إجمالي العدد 100.

على سبيل المثال، يعرض الرمز أدناه أعلى نتيجة من قائمة الصدارة:

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score").LimitToLast(1);

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

الفلترة حسب المفتاح أو القيمة

يمكنك استخدام StartAt() وEndAt() وEqualTo() لاختيار نقاط بداية ونهاية وتكافؤ عشوائية لطلبات البحث. يمكن أن يكون هذا مفيدًا لتقسيم البيانات إلى صفحات أو العثور على عناصر ذات عناصر فرعية لها قيمة محددة.

كيفية ترتيب بيانات طلب البحث

يوضّح هذا القسم كيفية ترتيب البيانات حسب كل طريقة من طرق الترتيب في فئة Query.

OrderByChild

عند استخدام OrderByChild()، يتم ترتيب البيانات التي تحتوي على المفتاح الفرعي المحدد على النحو التالي:

  1. تظهر أولاً العناصر الفرعية التي لها قيمة null لمفتاح الطفل المحدّد.
  2. تأتي بعد ذلك العناصر الثانوية التي لها القيمة false للمفتاح الثانوي المحدّد. إذا كان لدى عدة عناصر فرعية قيمة false، يتم ترتيبها معجميًا حسب المفتاح.
  3. تأتي بعد ذلك العناصر الثانوية التي لها القيمة true للمفتاح الثانوي المحدّد. إذا كان لدى عدة عناصر فرعية قيمة true، يتم ترتيبها معجميًا حسب المفتاح.
  4. تأتي بعد ذلك العناصر الثانوية التي لها قيمة رقمية، ويتم ترتيبها تصاعديًا. إذا كان هناك عدة عناصر فرعية لها القيمة الرقمية نفسها للعقدة الفرعية المحددة، يتم ترتيبها حسب المفتاح.
  5. تأتي السلاسل بعد الأرقام ويتم ترتيبها معجميًا بترتيب تصاعدي. إذا كان لدى عدة عناصر فرعية القيمة نفسها للعقدة الفرعية المحددة، يتم ترتيبها معجميًا حسب المفتاح.
  6. تأتي العناصر في النهاية ويتم ترتيبها معجميًا حسب المفتاح بترتيب تصاعدي.

OrderByKey

عند استخدام OrderByKey() لترتيب بياناتك، يتم عرض البيانات بترتيب تصاعدي حسب المفتاح.

  1. تظهر أولاً العناصر الفرعية التي تحتوي على مفتاح يمكن تحليله كعدد صحيح مكوّن من 32 بت، ويتم ترتيبها تصاعديًا.
  2. بعد ذلك، يتم ترتيب العناصر الثانوية التي تحتوي على قيمة سلسلة كمفتاح لها، ويتم ترتيبها معجميًا تصاعديًا.

OrderByValue

عند استخدام OrderByValue()، يتم ترتيب العناصر الفرعية حسب قيمتها. معايير الترتيب هي نفسها في OrderByChild()، باستثناء أنّه يتم استخدام قيمة العقدة بدلاً من قيمة مفتاح فرعي محدّد.

الخطوات التالية