استرداد البيانات باستخدام قاعدة بيانات 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<firebase::database::DataSnapshot> result =
    dbRef.GetReference("Leaders").GetValue();

عند تقديم الطلب، علينا الانتظار حتى يكتمل المستقبل قبل أن نتمكّن من قراءة القيمة. ونظرًا لأن الألعاب عادةً ما تعمل بشكل متكرر، ولا تعتمد على معاودة الاتصال كثيرًا، يتم عادةً إجراء استطلاع للاكتمال.

  // 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<firebase::database::DataSnapshot> 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<firebase::database::DataSnapshot> result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

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

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

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

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

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

يمكنك استخدام الفئة 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()، باستثناء قيمة العقدة المستخدَمة بدلاً من قيمة مفتاح فرعي محدّد.

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