אחזור נתונים

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

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

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

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

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

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

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

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

אחזור נתונים

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

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

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

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

אפשר להוסיף מאזינים לאירועים כדי להירשם לשינויים בנתונים:

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

האירוע ValueChanged

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

האירוע ChildChanged מופעל בכל פעם שצוין שינוי בצומת צאצא. זה כולל שינויים בכל הצאצאים של צומת הצאצא. בדרך כלל משתמשים בו בשילוב עם האירועים ChildAdded ו-ChildRemoved כדי להגיב לשינויים ברשימת פריטים. תמונת המצב (snapshot) שמועברת למאזין האירועים מכילה את הנתונים המעודכנים של הצאצא.

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

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

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

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

מיון נתונים

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

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

אפשר להשתמש רק בשיטה אחת לסדר את הרשימה בכל פעם. קריאה ל-method מסוג 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
    }

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

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

סינון נתונים

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

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

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

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

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

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

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

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

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

OrderByChild

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

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

OrderByKey

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

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

OrderByValue

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