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

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

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

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

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

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

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

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

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

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

Web

import { getDatabase, ref, push, set } from "firebase/database";

// Create a new post reference with an auto-generated id
const db = getDatabase();
const postListRef = ref(db, 'posts');
const newPostRef = push(postListRef);
set(newPostRef, {
    // ...
});

Web

// Create a new post reference with an auto-generated id
var postListRef = firebase.database().ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

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

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

אירוע שימוש רגיל
child_added אחזור רשימות של פריטים או האזנה להוספות לרשימת פריטים. האירוע הזה מופעל פעם אחת לכל צאצא קיים, ואז שוב בכל פעם שמתווסף צאצא חדש לנתיב שצוין. למאזין מועברת קובץ snapshot שמכיל את הנתונים של הצאצא החדש.
child_changed האזנה לשינויים בפריטים ברשימה. האירוע הזה מופעל בכל פעם שצומת צאצא משתנה. זה כולל כל שינוי בצאצאים של צומת הצאצא. תמונת המצב (snapshot) שמועברת למאזין האירועים מכילה את הנתונים המעודכנים של הצאצא.
child_removed האזנה לפריטים שמוסרים מרשימת פריטים. האירוע הזה מופעל כאשר צאצא מיידי מוסר.קובץ ה-snapshot שמוענק לבלוק של פונקציית ה-callback מכיל את הנתונים של הצאצא שהוסרה.
child_moved האזנה לשינויים בסדר הפריטים ברשימה מסודרת. אירועי child_moved תמיד מופיעים אחרי אירוע child_changed שגרם לשינוי הסדר של הפריט (על סמך שיטת הסדר הנוכחית).

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

Web

import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database";

const db = getDatabase();
const commentsRef = ref(db, 'post-comments/' + postId);
onChildAdded(commentsRef, (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

onChildChanged(commentsRef, (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

onChildRemoved(commentsRef, (data) => {
  deleteComment(postElement, data.key);
});

Web

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', (data) => {
  deleteComment(postElement, data.key);
});

האזנה לאירועי ערך

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

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

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

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const dbRef = ref(db, '/a/b/c');

onValue(dbRef, (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    const childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    // ...
  });
}, {
  onlyOnce: true
});

Web

ref.once('value', (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

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

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

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

מיון נתונים

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

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

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

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

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const myUserId = auth.currentUser.uid;
const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount'));

Web

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().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().

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";

const db = getDatabase();
const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views'));

Web

var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

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

סינון נתונים

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

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

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

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

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

כשהפריטים משתנים, אתם מקבלים אירועי child_added על פריטים שמתווספים לשאילתה ואירועי child_removed על פריטים שיוצאים ממנה, כך שהמספר הכולל נשאר 100.

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

Web

import { getDatabase, ref, query, limitToLast } from "firebase/database";

const db = getDatabase();
const recentPostsRef = query(ref(db, 'posts'), limitToLast(100));

Web

var recentPostsRef = firebase.database().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(), אלא שהערך של הצומת משמש במקום הערך של מפתח צאצא שצוין.

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

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

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

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

השלבים הבאים