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

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

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]) {
                  // ...
                }
              }];

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

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

يمكنك استخدام الفئة 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"];

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

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

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