עבודה עם רשימות נתונים בפלטפורמות של 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 אחזור רשימות של פריטים או האזנה להוספות לרשימת פריטים. האירוע הזה מופעל פעם אחת לכל צאצא קיים, ואז שוב בכל פעם שמתווסף צאצא חדש לנתיב שצוין. למאזין מועברת קובץ snapshot שמכיל את הנתונים של הצאצא החדש.
FIRDataEventTypeChildChanged האזנה לשינויים בפריטים ברשימה. האירוע הזה מופעל בכל פעם שצומת צאצא משתנה. זה כולל שינויים לכל הצאצאים של צומת הצאצא. תמונת המצב שמועברת למאזין האירועים מכילה את הנתונים המעודכנים של הצאצא.
FIRDataEventTypeChildRemoved האזנה לפריטים שמוסרים מרשימת פריטים. האירוע הזה מופעל כאשר צאצא מיידי מוסר.קובץ ה-snapshot שמוענק לבלוק של פונקציית ה-callback מכיל את הנתונים של הצאצא שהוסרה.
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 יחיד, שאפשר יהיה להריץ בו לולאה כדי לגשת לצאצאים ספציפיים.

גם אם יש רק התאמה אחת לשאילתה, קובץ snapshot עדיין יהיה רשימה, רק שהוא יכיל פריט אחד. כדי לגשת לפריט, צריך להריץ לולאה על התוצאה:

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 מיון התוצאות לפי הערך של מפתח צאצא או נתיב צאצא בתצוגת עץ שצוין.

אפשר להשתמש רק בשיטה אחת לסדר את הרשימה בכל פעם. קריאה ל-method מסוג order-by מספר פעמים באותה שאילתה תגרום לשגיאה.

בדוגמה הבאה מוסבר איך אפשר לאחזר רשימה של הפוסטים המובילים של משתמש, ממוינים לפי מספר הכוכבים שהם קיבלו:

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"];

השאילתה הזו מאחזרת את הפוסטים של המשתמש מהנתיב במסד הנתונים על סמך מזהה המשתמש שלו, ומסודרת לפי מספר הכוכבים שקיבל כל פוסט. השיטה הזו של שימוש במזהים כמפתחות של אינדקס נקראת 'הרחבת נתונים'. מידע נוסף זמין במאמר מבנה מסד הנתונים.

בקריאה ל-method‏ 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"];

מידע נוסף על סדר של סוגי נתונים אחרים זמין במאמר איך מתבצע הסדר של נתוני השאילתה.

סינון נתונים

כדי לסנן נתונים, אפשר לשלב כל אחת מהשיטות של limit או range עם שיטת order-by כשיוצרים שאילתה.

שיטה שימוש
queryLimitedToFirst מגדיר את המספר המקסימלי של פריטים להחזרה מתחילת רשימת התוצאות הממוזערת.
queryLimitedToLast מגדיר את המספר המקסימלי של פריטים להחזרה מסוף רשימת התוצאות הממוזערת.
queryStartingAtValue החזרת פריטים שגדולים מ-key או מ-value שצוינו או שווים להם, בהתאם לשיטת הסדר שנבחרה.
queryStartingAfterValue הפונקציה מחזירה פריטים שגדולים מהמפתח או מהערך שצוינו, בהתאם לשיטת הסדר שבחרתם.
queryEndingAtValue הפונקציה מחזירה פריטים שערכם קטן או שווה למפתח או לערך שצוינו, בהתאם לשיטת הסדר שנבחרה.
queryEndingBeforeValue החזרת פריטים שערכם קטן מהמפתח או מהערך שצוינו, בהתאם לשיטת הסדר שנבחרה.
queryEqualToValue הפונקציה מחזירה פריטים שווים למפתח או לערך שצוינו, בהתאם לשיטת הסדר שנבחרה.

בניגוד לשיטות order-by, אפשר לשלב כמה פונקציות של הגבלה או טווח. לדוגמה, אפשר לשלב את השיטות queryStartingAtValue ו-queryEndingAtValue כדי להגביל את התוצאות לטווח ערכים מסוים.

הגבלת מספר התוצאות

אפשר להשתמש בשיטות queryLimitedToFirst ו-queryLimitedToLast כדי להגדיר את מספר הצאצאים המקסימלי שיסונכרנו בקריאה חוזרת נתונה. לדוגמה, אם משתמשים ב-queryLimitedToFirst כדי להגדיר מגבלה של 100, בהתחלה מקבלים רק עד 100 קריאות חזרה של FIRDataEventTypeChildAdded. אם יש לכם פחות מ-100 פריטים שמאוחסנים במסד הנתונים של Firebase, תיגרם קריאה חוזרת (callback) של FIRDataEventTypeChildAdded לכל פריט.

כשהפריטים משתנים, אתם מקבלים FIRDataEventTypeChildAdded קריאות חזרה (callbacks) על פריטים שמתווספים לשאילתה ו-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 לא מפסיקים את סנכרון הנתונים באופן אוטומטי כשאתם יוצאים מהם. אם לא מסירים את הצופה בצורה נכונה, הוא ממשיך לסנכרן נתונים עם הזיכרון המקומי ולשמור את כל האובייקטים שצולמו ב-closure של טיפול האירוע, דבר שעלול לגרום לדליפות זיכרון. כשאין יותר צורך במתבונן, מעבירים את FIRDatabaseHandle המשויך ל-method‏ removeObserverWithHandle כדי להסיר אותו.

כשמוסיפים בלוק של קריאה חוזרת להפניה, מוחזר FIRDatabaseHandle. אפשר להשתמש במזהים האלה כדי להסיר את הבלוק של קריאת החזרה (callback).

אם הוספתם כמה מאזינים להפניה למסד נתונים, כל מאזין ייכלל כשאירוע יתרחש. כדי להפסיק את סנכרון הנתונים במיקום הזה, צריך להסיר את כל המשתמשים שמנטרלים את המיקום באמצעות קריאה ל-method‏ removeAllObservers.

קריאה ל-removeObserverWithHandle או ל-removeAllObservers על מאזין לא מסירה באופן אוטומטי מאזינים שרשומים בצמתים הצאצאים שלו. כדי להסיר אותם, צריך גם לעקוב אחרי ההפניות או כינויי המזהה האלה.

השלבים הבאים