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

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

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

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