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

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

لقراءة البيانات من قاعدة البيانات أو كتابتها فيها، تحتاج إلى مثيل من 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(). يؤدي استدعاء off() في الموقع بدون أي وسيطات إلى إزالة جميع المستمعين في هذا الموقع.

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

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