עבודה עם רשימות נתונים

אחזור של הפניה למסד נתונים

כדי לקרוא או לכתוב נתונים מהמסד הנתונים, צריך מופע של DatabaseReference:

DatabaseReference ref = FirebaseDatabase.instance.ref();

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

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

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

אפשר להשתמש בהפניה לנתונים החדשים שמוחזרים על ידי השיטה push() כדי לקבל את הערך של המפתח שנוצר באופן אוטומטי של הצאצא, או כדי להגדיר נתונים עבור הצאצא. המאפיין .key של הפניה push() מכיל את המפתח שנוצר באופן אוטומטי.

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

לדוגמה, אפשר להשתמש ב-push() כדי להוסיף פוסט חדש לרשימת פוסטים באפליקציה חברתית:

DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
  // ...
});

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

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

אירוע שימוש רגיל
onChildAdded אחזור רשימות של פריטים או האזנה להוספות לרשימת פריטים. האירוע הזה מופעל פעם אחת לכל צאצא קיים, ואז בכל פעם שמתווסף צאצא חדש לנתיב שצוין. למאזין מועברת קובץ snapshot שמכיל את הנתונים של הצאצא החדש.
onChildChanged האזנה לשינויים בפריטים ברשימה. האירוע הזה מופעל בכל פעם שצומת צאצא משתנה. זה כולל כל שינוי בצאצאים של צומת הצאצא. קובץ ה-snapshot שמועבר ל-event listener מכיל את הנתונים המעודכנים של הילד או הילדה.
onChildRemoved האזנה לפריטים שהוסרו מרשימה. האירוע הזה מופעל כאשר צאצא ישיר מסוים מוסר. קובץ ה-snapshot שמוענק לבלוק של פונקציית ה-callback מכיל את הנתונים של הצאצא שהוסרו.
onChildMoved האזנה לשינויים בסדר הפריטים ברשימה מסודרת. אירועי onChildTransfer תמיד פועלים לפי האירוע onChildChanged שגרם לשינוי בסדר הפריט (בהתאם לשיטה הנוכחית של 'סידור לפי').

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

final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
  // A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
  // A comment has changed; use the key to determine if we are displaying this
  // comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
  // A comment has been removed; use the key to determine if we are displaying
  // this comment and if so remove it.
});

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

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

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

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

myTopPostsQuery.onValue.listen((event) {
  for (final child in event.snapshot.children) {
    // Handle the post.
  }
}, onError: (error) {
  // Error.
});

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

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

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

מיון נתונים

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

שיטה שימוש
orderByChild() מיון התוצאות לפי הערך של מפתח צאצא או נתיב צאצא בתצוגת עץ שצוין.
orderByKey() מיון התוצאות לפי מפתחות צאצאים.
orderByValue() מיון התוצאות לפי ערכי הצאצאים.

אפשר להשתמש רק בשיטה אחת בכל פעם. קריאה לשיטה 'סידור לפי' מספר פעמים באותה שאילתה, גורמת לשגיאה.

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

final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
    .ref("user-posts/$myUserId")
    .orderByChild("starCount");

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

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

final mostViewedPosts =
    FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');

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

סינון נתונים

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

שיטה שימוש
limitToFirst() מגדיר את המספר המקסימלי של פריטים להחזרה מתחילת רשימת התוצאות הממוזערת.
limitToLast() מגדיר את המספר המקסימלי של פריטים להחזרה מסוף רשימת התוצאות הממוזערת.
startAt() החזרת פריטים שגדולים מהמפתח או מהערך שצוינו או שווים להם, בהתאם לשיטת הסדר שנבחרה.
startAfter() הפונקציה מחזירה פריטים שגדולים מהמפתח או מהערך שצוינו, בהתאם לשיטת הסדר שנבחרה.
endAt() הפונקציה מחזירה פריטים שערכם קטן או שווה למפתח או לערך שצוינו, בהתאם לשיטת הסדר שנבחרה.
endBefore() הפונקציה מחזירה פריטים שערכם קטן מהמפתח או מהערך שצוינו, בהתאם לשיטת הסדר שנבחרה.
equalTo() הפונקציה מחזירה פריטים שווים למפתח או לערך שצוינו, בהתאם לשיטת הסדר שנבחרה.

בשונה מהשיטה 'סידור לפי שיטות', כאן אפשר לשלב מספר פונקציות של מגבלה או טווח. לדוגמה, אפשר לשלב את השיטות startAt() ו-endAt() כדי להגביל את התוצאות לטווח ערכים מסוים.

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

אפשר להשתמש בשיטות limitToFirst() ו-limitToLast() כדי להגדיר את מספר הצאצאים המקסימלי שיסונכרנו עבור אירוע נתון. לדוגמה, אם משתמשים ב-limitToFirst() כדי להגדיר מגבלה של 100, בהתחלה מקבלים רק עד 100 אירועי onChildAdded. אם יש לכם פחות מ-100 פריטים שמאוחסנים במסד הנתונים של Firebase, מתרחש אירוע onChildAdded לכל פריט.

כשפריטים משתנים, מקבלים אירועי onChildAdded לפריטים מזינים את השאילתה ואירועי onChildRemoved לפריטים שעוזבים, כך שהמספר הכולל נשאר 100.

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

final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);

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

סינון לפי מפתח או ערך

אפשר להשתמש ב-startAt(),‏ startAfter(),‏ endAt(),‏ endBefore() ו-equalTo() כדי לבחור נקודות התחלה, סיום ושוויון שרירותיות לשאילתות. האפשרות הזו יכולה להיות שימושית לחלוקת נתונים לדפים או לאיתור פריטים עם צאצאים שיש להם ערך ספציפי.

איך מתבצע הסדר של נתוני השאילתה

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

orderByChild

כשמשתמשים ב-orderByChild(), הנתונים שמכילים את מפתח הצאצא שצוין מסודרים כך:

  1. צאצאים עם ערך null למפתח הצאצא שצוין מופיעים קודם.
  2. לאחר מכן מופיעים צאצאים עם הערך false למפתח הצאצא שצוין. אם יש כמה צאצאים עם הערך false, הם ממוינים לפי אלפבית לפי מפתח.
  3. ילדים שהערך שלהם הוא true למפתח הצאצא שצוין יופיעו בהמשך. אם ליותר מילד אחד יש ערך של true, הם ממוינים לפי מפתח לפי סדר אלפביתי.
  4. לאחר מכן מופיעים צאצאים עם ערך מספרי, שממוינים בסדר עולה. אם ליותר מילד אחד יש את אותו ערך מספרי בצומת הצאצא שצוין, הם ממוינים לפי מפתח.
  5. מחרוזות מופיעות אחרי מספרים וממוינות לפי סדר אלפביתי עולה. אם לכמה צאצאים יש אותו ערך בצומת הצאצא שצוין, הם ממוינים לפי מפתח אלפביתי.
  6. האובייקטים מופיעים בסוף וממוינים לפי מפתח אלפביתי בסדר עולה.

orderByKey

כשמשתמשים ב-orderByKey() כדי למיין את הנתונים, הנתונים מוחזרים בסדר עולה לפי מפתח.

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

orderByValue

כשמשתמשים ב-orderByValue(), הצאצאים ממוינים לפי הערך שלהם. קריטריונים הסדר זהים לקריטריונים של orderByChild(), אלא שהערך של הצומת משמש במקום הערך של מפתח צאצא שצוין.

ניתוק של רכיבי מעקב

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

כדי להסיר מאזין יחיד, מעבירים אותו כפרמטר ל-off(). קריאה ל-off() במיקום ללא ארגומנטים תסיר את כל המאזינים מהמיקום הזה.

קריאה ל-off() על מאזין הורה לא מסירה באופן אוטומטי מאזינים שרשומים בצמתים הצאצאים שלו. צריך לקרוא ל-off() גם על כל מאזיני הצאצאים כדי להסיר את פונקציית ה-callback.

השלבים הבאים