العمل باستخدام قوائم البيانات على منصات 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 هذا على هدف "مقتطف التطبيق".
[_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 هذا على هدف "مقتطف التطبيق".
// 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"];

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

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

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

الطريقة الاستخدام
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 على مستمع إلى إزالة المستمعين المسجّلين على العُقد الفرعية تلقائيًا، بل عليك أيضًا تتبُّع تلك المراجع أو المقابض لإزالتها.

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