עבודה עם רשימות נתונים בפלטפורמות של 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];

רשימות קריאה וכתיבה

הוספה לרשימת נתונים

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

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

אתם יכולים להשתמש במפתחות שנוצרו באופן אוטומטי כדי לפשט את מבנה הנתונים. למידע נוסף, ראו דוגמה להרחבת נתונים.

האזנה לאירועים משניים

אירועים משניים מופעלים בתגובה לפעולות ספציפיות שמתרחשות בצאצאים של צומת, למשל הוספת צאצא חדש באמצעות השיטה childByAutoId או עדכון של צאצא באמצעות השיטה updateChildValues.

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

התבנית הזו יכולה להיות שימושית כשרוצים לאחזר את כל הצאצאים של רשימה בפעולה אחת, במקום להאזין לאירועים נוספים של הוספת צאצאים.

מיון וסינון של נתונים

אפשר להשתמש במחלקה 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"];

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

הקריאה ל-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 הזה לא זמין ביעד של 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 כדי להגדיר את המספר המקסימלי של צאצאים שיסונכרנו בקריאה חוזרת (callback) נתונה. לדוגמה, אם משתמשים ב-queryLimitedToFirst כדי להגדיר מגבלה של 100, בהתחלה מקבלים רק עד 100 קריאות חוזרות (callbacks) של FIRDataEventTypeChildAdded. אם יש לכם פחות מ-100 פריטים שמאוחסנים במסד הנתונים של Firebase, קריאה חוזרת (callback) של FIRDataEventTypeChildAdded מופעלת לכל פריט.

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

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

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

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

השלבים הבאים