العمل باستخدام قوائم البيانات

الحصول على مرجع قاعدة بيانات

لقراءة البيانات من قاعدة البيانات أو كتابتها، تحتاج إلى مثيل من DatabaseReference:

DatabaseReference ref = FirebaseDatabase.instance.ref();

قراءة القوائم وكتابتها

الإلحاق بقائمة بيانات

استخدِم طريقة push() لإلحاق البيانات بقائمة في التطبيقات المتعددة المستخدمين. تُنشئ طريقة push() مفتاحًا فريدًا في كل مرة تتم فيها إضافة عنصر فرعي جديد إلى مرجع Firebase المحدّد. باستخدام هذه المفاتيح التي يتم إنشاؤها تلقائيًا لكل عنصر جديد في القائمة، يمكن لعدة عملاء إضافة عناصر فرعية إلى الموقع نفسه في الوقت نفسه بدون تعارضات في الكتابة. يعتمد المفتاح الفريد الذي تم إنشاؤه بواسطة push() على طابع زمني، لذلك يتم ترتيب عناصر القائمة تلقائيًا ترتيبًا زمنيًا.

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

يمكنك استخدام هذه المفاتيح التي تم إنشاؤها تلقائيًا لتبسيط تسوية بنية بياناتك. لمزيد من المعلومات، يُرجى الاطّلاع على مثال على توزيع البيانات.

على سبيل المثال، يمكن استخدام push() لإضافة مشاركة جديدة إلى قائمة المشاركات في تطبيق اجتماعي:

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
  // ...
});

الاستماع إلى الأحداث الفرعية

يتم تشغيل الأحداث الفرعية استجابةً لعمليات محددة تحدث للأحداث الفرعية لعقدة من عملية مثل حدث فرعي جديد تمت إضافته من خلال طريقة push() أو حدث فرعي يتم تحديثه من خلال طريقة update().

الحدث الاستخدام المعتاد
onChildAdded استرداد قوائم العناصر أو الاستماع إلى الإضافات إلى قائمة العناصر يتم تشغيل هذا الحدث مرة واحدة لكل عنصر فرعي حالي ثم مرة أخرى في كل مرة تتم فيها إضافة عنصر فرعي جديد إلى المسار المحدد. يتم تمرير لقطة تحتوي على بيانات الطفل الجديد إلى المستمع.
onChildChanged الاستماع إلى التغييرات التي تطرأ على العناصر في قائمة يتم تشغيل هذا الحدث في أي وقت يتم فيه تعديل عقدة فرعية. ويشمل ذلك أي تعديلات على العناصر التابعة للعقدة الفرعية. وتحتوي اللقطة التي تم تمريرها إلى متتبِّع الأحداث على البيانات المعدَّلة للعنصر الفرعي.
onChildRemoved الاستماع إلى العناصر التي تتم إزالتها من القائمة يتم تشغيل هذا الحدث عند إزالة عنصر فرعي مباشر.تحتوي اللقطة التي تم تمريرها إلى كتلة رد الاتصال على بيانات العنصر الفرعي الذي تمت إزالته.
onChildMoved تتبّع التغييرات في ترتيب العناصر في قائمة مع ترتيب. تتبع أحداث onChildMoved دائمًا حدث onChildChanged الذي تسبب في تغيير ترتيب العنصر (بناءً على طريقة الترتيب الحالية).

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

final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
  // A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
  // A comment has changed; use the key to determine if we are displaying this
  // comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
  // A comment has been removed; use the key to determine if we are displaying
  // this comment and if so remove it.
});

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

على الرغم من أنّ الاستماع إلى الأحداث الفرعية هو الطريقة المقترَحة لقراءة قوائم البيانات، هناك حالات يكون فيها الاستماع إلى أحداث القيمة في مرجع قائمة مفيدًا.

سيؤدي إرفاق مستمع value بقائمة من البيانات إلى عرض قائمة البيانات بأكملها كلقطة واحدة يمكنك بعد ذلك تكرارها للوصول إلى العناصر الفرعية الفردية.

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

myTopPostsQuery.onValue.listen((event) {
  for (final child in event.snapshot.children) {
    // Handle the post.
  }
}, onError: (error) {
  // Error.
});

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

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

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

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

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

الطريقة الاستخدام
orderByChild() يمكنك ترتيب النتائج حسب قيمة مفتاح فرعي محدّد أو مسار فرعي مدمج.
orderByKey() ترتيب النتائج حسب المفاتيح الفرعية
orderByValue() ترتيب النتائج حسب القيم الفرعية

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

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

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
    .ref("user-posts/$myUserId")
    .orderByChild("starCount");

يحدّد هذا طلب بحث عند دمجه مع أداة استماع فرعية يعمل على مزامنة العميل مع مشاركات المستخدم من المسار في قاعدة البيانات بناءً على رقم تعريف المستخدم، ويتم ترتيبها حسب عدد النجوم التي حصلت عليها كل مشاركة. يُطلق على أسلوب استخدام المعرّفات كمفاتيح فهرسة اسم "توزيع البيانات"، ويمكنك الاطّلاع على مزيد من المعلومات عنه في مقالة بناء قاعدة بياناتك.

يحدّد استدعاء طريقة orderByChild() المفتاح الفرعي لترتيب النتائج حسبه. في هذه الحالة، يتم ترتيب المشاركات حسب قيمة العنصر الثانوي "starCount" الخاص بها. يمكن أيضًا ترتيب طلبات البحث حسب العناصر الفرعية المتداخلة، في حال كانت لديك بيانات تبدو على النحو التالي:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

في هذه الحالة، يمكننا ترتيب عناصر القائمة حسب القيم المضمّنة ضمن المفتاح metrics من خلال تحديد المسار النسبي للعنصر الثانوي المضمّن في طلب orderByChild().

final mostViewedPosts =
    FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');

لمزيد من المعلومات حول كيفية ترتيب أنواع البيانات الأخرى، يُرجى الاطّلاع على كيفية ترتيب بيانات طلبات البحث.

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

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

الطريقة الاستخدام
limitToFirst() تحدّد هذه المَعلمة الحد الأقصى لعدد العناصر التي سيتم عرضها من بداية قائمة النتائج المرتبة.
limitToLast() تحدّد هذه المَعلمة الحد الأقصى لعدد العناصر التي يتم عرضها من نهاية قائمة النتائج المرتبة.
startAt() عرض العناصر الأكبر من أو تساوي المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب التي تم اختيارها
startAfter() عرض العناصر الأكبر من المفتاح أو القيمة المحدّدة استنادًا إلى طريقة الترتيب التي تم اختيارها
endAt() عرض العناصر التي تكون أقل من أو تساوي المفتاح أو القيمة المحدّدة، حسب طريقة الترتيب التي تم اختيارها
endBefore() عرض العناصر التي تكون أقل من المفتاح أو القيمة المحدّدة حسب طريقة الترتيب التي تم اختيارها
equalTo() عرض العناصر التي تساوي المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب التي تم اختيارها

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

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

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

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

يوضّح المثال التالي كيفية تحديد تطبيق تدوين نموذجي لطلب بحث من أجل استرداد قائمة بأحدث 100 مشاركة من جميع المستخدمين:

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

يحدّد هذا المثال طلب بحث فقط، ولمزامنة البيانات فعليًا، يجب أن يكون لديه مستمع مرفق.

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

يمكنك استخدام startAt() وstartAfter() وendAt() وendBefore() وequalTo() لاختيار نقاط بداية ونهاية وتكافؤ عشوائية لطلبات البحث. ويمكن أن يكون ذلك مفيدًا لتقسيم البيانات إلى صفحات أو العثور على عناصر فرعية لها قيمة معيّنة.

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

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

orderByChild

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

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

orderByKey

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

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

orderByValue

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

فصل المستمعين

تتم إزالة عمليات الاستدعاء من خلال استدعاء طريقة off() في مرجع قاعدة بيانات Firebase.

يمكنك إزالة مستمع واحد من خلال تمريره كمَعلمة إلى off(). Calling off() on the location with no arguments removes all listeners at that location.

لا يؤدي استدعاء off() على مستمع رئيسي إلى إزالة المستمعين المسجّلين على العُقد الفرعية تلقائيًا، بل يجب أيضًا استدعاء off() على أي مستمعين فرعيين لإزالة دالة الاستدعاء.

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