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

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

قبل البدء

قبل أن تتمكّن من استخدام قاعدة بيانات الوقت الفعلي، عليك إجراء ما يلي:

  • سجِّل مشروعك على Unity واضبطه لاستخدام Firebase.

    • إذا كان مشروعك في Unity يستخدم Firebase في الوقت الحالي، يعني ذلك أنّه تم تسجيله وإعداده من أجل Firebase.

    • إذا لم يكن لديك مشروع على Unity، يمكنك تنزيل نموذج تطبيق.

  • أضِف حزمة تطوير برامج Unity من Firebase (خصوصًا FirebaseDatabase.unitypackage) إلى مشروع Unity.

تجدر الإشارة إلى أنّ إضافة Firebase إلى مشروع Unity تتضمّن مهام في وحدة تحكُّم Firebase وفي مشروع Unity المفتوح (على سبيل المثال، يمكنك تنزيل ملفات إعدادات Firebase من وحدة التحكّم، ثم نقلها إلى مشروع Unity).

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

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

الحصول على DatabaseReference

لقراءة البيانات من قاعدة البيانات، أنت بحاجة إلى نسخة افتراضية من DatabaseReference:

using Firebase;
using Firebase.Database;
using Firebase.Extensions.TaskExtension; // for ContinueWithOnMainThread

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

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

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

    FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWithOnMainThread(task => {
        if (task.IsFaulted) {
          // Handle the error...
        }
        else if (task.IsCompleted) {
          DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
        }
      });

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

يمكنك إضافة أدوات معالجة الأحداث للاشتراك في التغييرات التي تطرأ على البيانات:

الحدث معدّل الاستخدام
ValueChanged قراءة التغييرات التي تتم على محتوى المسار بالكامل والاستماع إليها
ChildAdded استرداد قوائم العناصر أو الاستماع إلى الإضافات إلى قائمة من العناصر. تم اقتراح الاستخدام مع ChildChanged وChildRemoved لمراقبة التغييرات في القوائم.
ChildChanged رصد التغييرات على العناصر في القائمة يمكنك استخدامها مع ChildAdded وChildRemoved لمراقبة التغييرات في القوائم.
ChildRemoved رصد العناصر التي تتم إزالتها من القائمة يمكنك استخدامها مع ChildAdded وChildChanged لمراقبة التغييرات في القوائم.
ChildMoved الاستماع إلى التغييرات التي تطرأ على ترتيب العناصر في قائمة مع ترتيب تتّبع أحداث ChildMoved دائمًا حدث ChildChanged الذي تسبّب في تغيير ترتيب السلعة (استنادًا إلى طريقة الترتيب الحالية).

حدث ValueChanged

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

يحتوي ValueChangedEventArgs على DataSnapshot يحتوي على البيانات في الموقع الجغرافي المحدّد في قاعدة البيانات وقت الفعالية. يؤدي استدعاء Value على لقطة إلى عرض Dictionary<string, object> الذي يمثل البيانات. وفي حال عدم توفّر بيانات في الموقع الجغرافي، يعرض الاتصال بـ Value القيمة null.

في هذا المثال، يتم فحص args.DatabaseError أيضًا لمعرفة ما إذا تم إلغاء القراءة. على سبيل المثال، يمكن إلغاء القراءة إذا لم يكن لدى العميل إذن بالقراءة من موقع قاعدة بيانات Firebase. وستشير DatabaseError إلى سبب حدوث الفشل.

يمكنك لاحقًا إلغاء الاشتراك في الحدث باستخدام أي DatabaseReference يتضمن المسار نفسه. مثيلات DatabaseReference مؤقتة ويمكن التفكير فيها كطريقة للوصول إلى أي مسار وطلب بحث.

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged -= HandleValueChanged; // unsubscribe from ValueChanged.
    }

الأحداث الثانوية

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

      var ref = FirebaseDatabase.DefaultInstance
      .GetReference("GameSessionComments");

      ref.ChildAdded += HandleChildAdded;
      ref.ChildChanged += HandleChildChanged;
      ref.ChildRemoved += HandleChildRemoved;
      ref.ChildMoved += HandleChildMoved;
    }

    void HandleChildAdded(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildChanged(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildRemoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildMoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

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

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

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

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

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

فرز البيانات

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

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

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

يحدد استدعاء الإجراء OrderByChild() المفتاح الفرعي لترتيب النتائج حسبه. في هذه الحالة، يتم ترتيب النتائج حسب قيمة القيمة "score" في كل عنصر فرعي. لمزيد من المعلومات حول كيفية ترتيب أنواع البيانات الأخرى، راجِع كيفية ترتيب بيانات طلبات البحث.

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

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

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

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

حتى عندما يكون هناك تطابق واحد فقط للاستعلام، فإن اللقطة لا تزال قائمة؛ بل تحتوي فقط على عنصر واحد.

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

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

ومع تغيُّر العناصر، ستتلقّى ChildAdded طلبات معاودة الاتصال للعناصر التي تُدخل طلب البحث وChildRemoved عمليات استدعاء للعناصر التي يتم الانسحاب منها حتى يظل العدد الإجمالي هو 100.

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score").LimitToLast(1)
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

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