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

الحصول على FIRDatabaseReference

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في هدف App Clip.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

ملاحظة: لا يتوفّر منتج Firebase هذا في هدف App Clip.
@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 هذا في هدف App Clip.
// 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 هذا في هدف App Clip.
// 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 بقائمة من البيانات إلى عرض قائمة البيانات بالكامل كلقطة بيانات واحدة، والتي يمكنك بعد ذلك تكرارها للوصول إلى العناصر الفرعية الفردية.

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في هدف App Clip.
_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 يمكنك ترتيب النتائج حسب قيمة مفتاح فرعي محدّد أو مسار فرعي مدمج.

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

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

Swift

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

Objective-C

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

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

The call to the queryOrderedByChild method specifies the child key to order the results by. في هذا المثال، يتم ترتيب المشاركات حسب قيمة الفرع "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 هذا في هدف App Clip.
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

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

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

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

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

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

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

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

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

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

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

Swift

ملاحظة: لا يتوفّر منتج Firebase هذا في هدف App Clip.
// 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 هذا في هدف App Clip.
// 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 على مستمع إلى إزالة المستمعين المسجلين على العُقد الفرعية تلقائيًا، بل يجب أيضًا تتبُّع هذه المراجع أو المعالجات لإزالتها.

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