אחזור נתונים

במסמך הזה נסביר את העקרונות הבסיסיים של אחזור נתונים ואת הדרכים למיון ולסינון של נתוני 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 =&gt {
        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 כדי להירשם לגבי שינויים בתוכן בנתיב נתון. האירוע הזה מופעל פעם אחת כשמצרפים את ה-listener ופעם נוספת בכל פעם שהנתונים (כולל צאצאים) משתנים. בקריאה החוזרת (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 עדיין הוא רשימה, אלא שהוא מכיל רק פריט אחד.

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

אפשר להשתמש ב-methods LimitToFirst() ו-LimitToLast() כדי להגדיר מספר מקסימלי של צאצאים שיסונכרנו בקריאה חוזרת (callback) נתונה. לדוגמה, אם משתמשים ב-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(), אלא שהערך של הצומת משמש במקום הערך של מפתח צאצא שצוין.