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

الحصول على عنصر FIRDatabaseReference

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

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

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

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

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

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

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

يتم بدء أحداث العناصر الفرعية استجابةً لعمليات معيّنة تحدث ل العناصر الفرعية للعقدة من عملية، مثل إضافة عنصر فرعي جديد من خلال الأسلوب childByAutoId أو تعديل عنصر فرعي من خلال الأسلوب updateChildValues.

نوع الحدث الاستخدام المعتاد
FIRDataEventTypeChildAdded استرداد قوائم العناصر أو الاستماع إلى الإضافات إلى قائمة من العناصر. يتم تشغيل هذا الحدث مرة واحدة لكل مؤسسة فرعية حالية ثم مرة أخرى في كل مرة تتم فيها إضافة عنصر ثانوي جديد إلى المسار المحدد. يتم منح المستمع لقطة تحتوي على بيانات الطفل الجديد.
FIRDataEventTypeChildChanged الاستماع إلى التغييرات في العناصر ضمن قائمة يتم تشغيل هذا الحدث في أي وقت يتم فيه تعديل عقدة فرعية. ويشمل ذلك أي تعديلات على العناصر الفرعية للعقدة الفرعية. تحتوي اللقطة التي تم تمريرها إلى مستمع الحدث على البيانات المعدَّلة للعنصر الطفل.
FIRDataEventTypeChildRemoved استمع إلى العناصر التي تتم إزالتها من قائمة. يتم تشغيل هذا الحدث عند إزالة عنصر ثانوي مباشر.تحتوي اللقطة التي يتم تمريرها إلى مجموعة معاودة الاتصال على بيانات الطفلة التي تمت إزالتها.
FIRDataEventTypeChildMoved استمع إلى التغييرات في ترتيب العناصر في قائمة مرتبة. يتم تشغيل هذا الحدث عندما يؤدي تحديث إلى إعادة ترتيب العنصر الفرعي. ويتم استخدام هذه القيمة مع البيانات المرتبة حسب queryOrderedByChild أو queryOrderedByValue.

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

رصد أحداث القيم

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

سيؤدي إرفاق مراقب FIRDataEventTypeValue بقائمة بيانات إلى عرض القائمة الكاملة للبيانات كنسخة واحدة من DataSnapshot، ويمكنك بعد ذلك تكرار الإجراء لمحاولة الوصول إلى الأطفال الفرديين.

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في هدف App Clip.
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

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

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

يمكنك استخدام فئة Realtime Database FIRDatabaseQuery لاسترداد البيانات مفروضة الترتيب حسب المفتاح أو القيمة أو قيمة العنصر الفرعي. يمكنك أيضًا فلترة النتيجة المرتبطة بعدد معيّن من النتائج أو نطاق من المفاتيح أو القيم.

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

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

الطريقة الاستخدام
queryOrderedByKey يمكنك ترتيب النتائج حسب المفاتيح الثانوية.
queryOrderedByValue ترتيب النتائج حسب القيم الثانوية
queryOrderedByChild ترتيب النتائج حسب قيمة مفتاح فرعي محدّد أو مسار فرعي متداخل

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

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

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

تحدِّد الدعوة إلى الطريقة queryOrderedByChild مفتاح الطفل لترتيب النتائج حسبه. في هذا المثال، يتم ترتيب المشاركات حسب قيمة العنصر الفرعي "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 من خلال تحديد المسار النسبي للعنصر الثانوي المُدمج في طلب queryOrderedByChild.

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

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

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

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

الطريقة الاستخدام
queryLimitedToFirst تُستخدَم لتحديد الحد الأقصى لعدد العناصر التي سيتم عرضها من بداية القائمة المرتبة للنتائج.
queryLimitedToLast تُستخدَم لضبط الحد الأقصى لعدد العناصر التي سيتم عرضها من نهاية قائمة النتائج مرتبةً.
queryStartingAtValue عرض العناصر التي تكون أكبر من أو تساوي المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب المحدّدة
queryStartingAfterValue عرض العناصر التي تكون أكبر من المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب المحدّدة
queryEndingAtValue عرض العناصر التي تكون قيمتها أقل من المفتاح أو القيمة المحدّدة أو مساوية لهما، استنادًا إلى طريقة الترتيب المحدّدة
queryEndingBeforeValue عرض السلع التي تقلّ عن المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب المحدّدة
queryEqualToValue عرض العناصر التي تساوي المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب التي تم اختيارها

على عكس طرق "الترتيب حسب"، يمكنك دمج عدّة دوالّ حدّ أو نطاق. على سبيل المثال، يمكنك دمج الطريقتَين queryStartingAtValue وqueryEndingAtValue للحدّ من النتائج إلى نطاق محدّد من القيم.

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

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

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

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في استهداف "المقاطع الترويجية للتطبيقات".
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

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

يمكنك استخدام queryStartingAtValue وqueryStartingAfterValue queryEndingAtValue وqueryEndingBeforeValue وqueryEqualToValue لاختيار نقاط بداية وانتهاء ومعادلة عشوائية للطلبات. يمكن أن يكون هذا الإجراء مفيداً لتقسيم البيانات إلى صفحات أو للعثور على عناصر لها عناصر فرعية ذات قيمة معيّنة.

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

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

queryOrderedByKey

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

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

queryOrderedByValue

عند استخدام queryOrderedByValue، يتم ترتيب العناصر الثانوية حسب قيمتها. تكون معايير الترتيب نفسها كما في queryOrderedByChild، باستثناء أنّه يتم استخدام قيمة العقدة بدلاً من قيمة مفتاح فرعي محدّد.

queryOrderedByChild

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

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

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

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

عند إضافة كتلة طلب معاودة الاتصال إلى مرجع، يتم عرض FIRDatabaseHandle. يمكن استخدام هذه الأسماء المعرِّفة لإزالة القسم المخصّص لطلب معاودة الاتصال.

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

إنّ استدعاء removeObserverWithHandle أو removeAllObservers على مستمع لا يؤدي تلقائيًا إلى إزالة المستمعين المسجّلين في العقد الفرعية، بل يجب أيضًا تتبُّع هذه الإشارات أو الأسماء المعرِّفة لإزالتها.

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