استرداد البيانات باستخدام قاعدة بيانات 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 callback عند إزالة عنصر فرعي مباشر. ويُستخدَم عادةً مع عمليات الرجوع 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 إلى مزامنة العميل مع قائمة الصدارة في قاعدة البيانات، ويتم ترتيبها حسب نتيجة كل إدخال. يمكنك الاطّلاع على مزيد من المعلومات حول تنظيم بياناتك بكفاءة في مقالة تنظيم قاعدة البيانات.

يحدّد استدعاء الطريقة OrderByChild() مفتاح العنصر الفرعي لترتيب النتائج حسبه. في هذه الحالة، يتم ترتيب النتائج حسب قيمة "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()، باستثناء أنّه يتم استخدام قيمة العقدة بدلاً من قيمة مفتاح فرعي محدّد.

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