אחזור נתונים

במסמך הזה נסביר איך לאחזר נתונים, ואיך למיין ולסנן נתונים ב-Firebase.

לפני שמתחילים

כדי להשתמש ב-Realtime Database, צריך:

  • רושמים את הפרויקט ב-Unity ומגדירים אותו לשימוש ב-Firebase.

    • אם פרויקט Unity שלכם כבר משתמש ב-Firebase, הוא כבר רשום ומותאם ל-Firebase.

    • אם אין לכם פרויקט Unity, אתם יכולים להוריד אפליקציה לדוגמה.

  • מוסיפים את Firebase Unity SDK (במיוחד את FirebaseDatabase.unitypackage) לפרויקט Unity.

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

אחזור נתונים

הנתונים של Firebase מאוחזרים באמצעות קריאה חד-פעמית ל-GetValueAsync() או באמצעות צירוף לאירוע בהפניה FirebaseDatabase. הפונקציה event listener מופעלת פעם אחת עבור המצב הראשוני של הנתונים, ושוב בכל פעם שהנתונים משתנים.

קבלת DatabaseReference

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

using Firebase;
using Firebase.Database;
using Firebase.Extensions.TaskExtension; // for ContinueWithOnMainThread

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

קריאת נתונים פעם אחת

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

    FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWithOnMainThread(task =&gt {
        if (task.IsFaulted) {
          // Handle the error...
        }
        else if (task.IsCompleted) {
          DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
        }
      });

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

אתם יכולים להוסיף פונקציות event listener כדי להירשם לשינויים בנתונים:

אירוע שימוש אופייני
ValueChanged קריאה והאזנה לשינויים בכל התוכן של נתיב.
ChildAdded אחזור רשימות של פריטים או האזנה להוספות לרשימה של פריטים. מומלץ להשתמש ב-ChildChanged וב-ChildRemoved כדי לעקוב אחרי שינויים ברשימות.
ChildChanged חיפוש שינויים בפריטים ברשימה. אפשר להשתמש ב-ChildAdded וב-ChildRemoved כדי לעקוב אחרי שינויים ברשימות.
ChildRemoved האזנה להסרה של פריטים מרשימה. אפשר להשתמש ב-ChildAdded וב-ChildChanged כדי לעקוב אחרי שינויים ברשימות.
ChildMoved האזנה לשינויים בסדר של פריטים ברשימה מסודרת. אירועי ChildMoved תמיד מתרחשים אחרי אירוע ChildChanged שגרם לשינוי בסדר הפריטים (על סמך שיטת המיון הנוכחית).

אירוע ValueChanged

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

ValueChangedEventArgs מכיל DataSnapshot שמכיל את הנתונים במיקום שצוין במסד הנתונים בזמן האירוע. קריאה ל-Value בתמונת מצב מחזירה Dictionary<string, object> שמייצג את הנתונים. אם אין נתונים במיקום, הקריאה ל-Value מחזירה null.

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged -= HandleValueChanged; // unsubscribe from ValueChanged.
    }

אירועים משוכפלים

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

      var ref = FirebaseDatabase.DefaultInstance
      .GetReference("GameSessionComments");

      ref.ChildAdded += HandleChildAdded;
      ref.ChildChanged += HandleChildChanged;
      ref.ChildRemoved += HandleChildRemoved;
      ref.ChildMoved += HandleChildMoved;
    }

    void HandleChildAdded(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildChanged(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildRemoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildMoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

האירוע ChildChanged מתרחש בכל פעם שמשנים צומת צאצא. זה כולל שינויים בצאצאים של צומת הצאצא. בדרך כלל משתמשים בו יחד עם האירועים ChildAdded ו-ChildRemoved כדי להגיב לשינויים ברשימת פריטים. התמונה שמועברת לרכיב event listener מכילה את הנתונים המעודכנים של הצאצא.

האירוע ChildRemoved מופעל כשמסירים צאצא מיידי. בדרך כלל משתמשים בו בשילוב עם קריאות החזרה ChildAdded ו-ChildChanged. תמונת המצב שמועברת לקריאת ההחזרה של האירוע מכילה את הנתונים של הצאצא שהוסר.

האירוע ChildMoved מופעל בכל פעם שהאירוע ChildChanged מופעל על ידי עדכון שגורם לשינוי הסדר של הילד. הוא משמש עם נתונים שמסודרים לפי OrderByChild או OrderByValue.

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

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

מיון נתונים

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

שיטה שימוש
OrderByChild() מיון התוצאות לפי הערך של מפתח צאצא שצוין.
OrderByKey() ממיינים את התוצאות לפי מפתחות צאצא.
OrderByValue() מיון התוצאות לפי ערכי הצאצא.

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

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

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

סינון נתונים

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

שיטה שימוש
LimitToFirst() מגדיר את המספר המקסימלי של פריטים שיוחזרו מתחילת הרשימה הממוינת של התוצאות.
LimitToLast() מגדיר את המספר המקסימלי של פריטים שיוחזרו מסוף הרשימה הממוינת של התוצאות.
StartAt() הפונקציה מחזירה פריטים שגדולים מהמפתח או מהערך שצוינו או שווים להם, בהתאם לשיטת המיון שנבחרה.
EndAt() הפונקציה מחזירה פריטים שקטנים מהמפתח או מהערך שצוינו או שווים להם, בהתאם לשיטת המיון שנבחרה.
EqualTo() הפונקציה מחזירה פריטים ששווים למפתח או לערך שצוינו, בהתאם לשיטת המיון שנבחרה.

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

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

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

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

כשהפריטים משתנים, מקבלים קריאות חוזרות (callback) מסוג ChildAdded לפריטים שנכנסים לשאילתה וקריאות חוזרות מסוג ChildRemoved לפריטים שיוצאים ממנה, כך שהמספר הכולל נשאר 100.

לדוגמה, הקוד הבא מחזיר את הציון הכי גבוה מטבלת מובילים:

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score").LimitToLast(1)
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

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

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

איך נתוני השאילתות מסודרים

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

OrderByChild

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

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

OrderByKey

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

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

OrderByValue

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