מסמך זה מכסה את היסודות של אחזור נתוני מסד נתונים, אופן סדר הנתונים וכיצד לבצע שאילתות פשוטות על נתונים. אחזור נתונים ב-Admin SDK מיושם באופן מעט שונה בשפות תכנות שונות.
- מאזינים אסינכרוניים: נתונים המאוחסנים במסד נתונים בזמן אמת של Firebase מאוחזרים על ידי צירוף מאזין אסינכרוני להפניה למסד נתונים. המאזין מופעל פעם אחת עבור המצב ההתחלתי של הנתונים ושוב בכל פעם שהנתונים משתנים. מאזין אירועים עשוי לקבל מספר סוגים שונים של אירועים . מצב זה של אחזור נתונים נתמך ב-Java, Node.js ו- Python Admin SDK.
- החסימה כתובה: נתונים המאוחסנים במסד נתונים בזמן אמת של Firebase מאוחזרים על ידי הפעלת שיטת חסימה בהפניה למסד נתונים, אשר מחזירה את הנתונים המאוחסנים בהפניה. כל קריאת שיטה היא פעולה חד פעמית. זה אומר שה-SDK לא רושם כל התקשרות חוזרת שמאזינה לעדכוני נתונים הבאים. מודל זה של אחזור נתונים נתמך ב- Python ו- Go Admin SDK.
מתחילים
בואו נסתכל שוב על דוגמה לבלוגים מהמאמר הקודם כדי להבין כיצד לקרוא נתונים ממסד נתונים של Firebase. זכור שהפוסטים בבלוג באפליקציה לדוגמה מאוחסנים בכתובת האתר של מסד הנתונים https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json . כדי לקרוא את נתוני הפוסטים שלך, אתה יכול לעשות את הפעולות הבאות:
Java
public static class Post { public String author; public String title; public Post(String author, String title) { // ... } } // Get a reference to our posts final FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("server/saving-data/fireblog/posts"); // Attach a listener to read the data at our posts reference ref.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Post post = dataSnapshot.getValue(Post.class); System.out.println(post); } @Override public void onCancelled(DatabaseError databaseError) { System.out.println("The read failed: " + databaseError.getCode()); } });
Node.js
// Get a database reference to our posts const db = getDatabase(); const ref = db.ref('server/saving-data/fireblog/posts'); // Attach an asynchronous callback to read the data at our posts reference ref.on('value', (snapshot) => { console.log(snapshot.val()); }, (errorObject) => { console.log('The read failed: ' + errorObject.name); });
פִּיתוֹן
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
ללכת
// Post is a json-serializable type. type Post struct { Author string `json:"author,omitempty"` Title string `json:"title,omitempty"` } // Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln("Error initializing database client:", err) } // Get a database reference to our posts ref := client.NewRef("server/saving-data/fireblog/posts") // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, &post); err != nil { log.Fatalln("Error reading value:", err) }
אם תפעיל את הקוד שלמעלה, תראה אובייקט המכיל את כל הפוסטים שלך מחוברים למסוף. במקרה של Node.js ו-Java, פונקציית המאזין נקראת בכל פעם שמתווספים נתונים חדשים להפניה למסד הנתונים שלך, ואתה לא צריך לכתוב שום קוד נוסף כדי לגרום לזה לקרות.
ב-Java וב-Node.js, פונקציית ה-callback מקבלת DataSnapshot
, שהיא תמונת מצב של הנתונים. תמונת מצב היא תמונה של הנתונים בהפניה מסוימת למסד נתונים בנקודת זמן אחת. קריאה ל- val()
/ getValue()
בתמונת מצב מחזירה את ייצוג האובייקט הספציפי לשפה של הנתונים. אם לא קיימים נתונים במיקום ההפניה, הערך של תמונת המצב הוא null
. השיטה get()
ב-Python מחזירה ייצוג Python של הנתונים ישירות. הפונקציה Get()
ב-Go משחררת את הנתונים למבנה נתונים נתון.
שימו לב שהשתמשנו בסוג אירוע value
בדוגמה שלמעלה, שקורא את כל התוכן של הפניה למסד נתונים של Firebase, גם אם רק נתון אחד השתנה. value
הוא אחד מחמשת סוגי האירועים השונים המפורטים להלן שבהם אתה יכול להשתמש כדי לקרוא נתונים ממסד הנתונים.
קרא סוגי אירועים ב-Java ו-Node.js
ערך
אירוע value
משמש לקריאת תמונת מצב סטטית של התוכן בנתיב מסד נתונים נתון, כפי שהם היו קיימים בזמן אירוע הקריאה. הוא מופעל פעם אחת עם הנתונים הראשוניים ושוב בכל פעם שהנתונים משתנים. ההתקשרות חזרה לאירוע מועברת תמונת מצב המכילה את כל הנתונים באותו מיקום, כולל נתוני ילדים. בדוגמה של הקוד למעלה, value
החזיר את כל הפוסטים בבלוג באפליקציה שלך. בכל פעם שמתווסף פוסט חדש בבלוג, פונקציית ההתקשרות חוזרת תחזיר את כל הפוסטים.
ילד נוסף
אירוע child_added
משמש בדרך כלל בעת אחזור רשימה של פריטים ממסד הנתונים. בניגוד ל- value
שמחזיר את כל התוכן של המיקום, child_added
מופעל פעם אחת עבור כל ילד קיים ואז שוב בכל פעם שילד חדש מתווסף לנתיב שצוין. ההתקשרות חזרה לאירוע מועברת תמונת מצב המכילה את הנתונים של הילד החדש. לצורכי הזמנה, הוא מועבר גם ארגומנט שני המכיל את המפתח של הילד הקודם.
אם אתה רוצה לאחזר רק את הנתונים על כל פוסט חדש שנוסף לאפליקציית הבלוגים שלך, תוכל להשתמש child_added
:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Post newPost = dataSnapshot.getValue(Post.class); System.out.println("Author: " + newPost.author); System.out.println("Title: " + newPost.title); System.out.println("Previous Post ID: " + prevChildKey); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Retrieve new posts as they are added to our database ref.on('child_added', (snapshot, prevChildKey) => { const newPost = snapshot.val(); console.log('Author: ' + newPost.author); console.log('Title: ' + newPost.title); console.log('Previous Post ID: ' + prevChildKey); });
בדוגמה זו תמונת המצב תכיל אובייקט עם פוסט בודד בבלוג. מכיוון שה-SDK ממיר פוסטים לאובייקטים על ידי אחזור הערך, יש לך גישה למאפייני המחבר והכותרת של הפוסט על ידי קריאה author
title
בהתאמה. יש לך גם גישה למזהה הפוסט הקודם מהארגומנט השני prevChildKey
.
הילד השתנה
האירוע child_changed
מופעל בכל פעם שצומת צאצא משתנה. זה כולל שינויים כלשהם בצאצאים של צומת הילד. הוא משמש בדרך כלל בשילוב עם child_added
ו- child_removed
כדי להגיב לשינויים ברשימת פריטים. תמונת המצב שהועברה להתקשרות חוזרת של האירוע מכילה את הנתונים המעודכנים עבור הילד.
אתה יכול להשתמש child_changed
כדי לקרוא נתונים מעודכנים בפוסטים בבלוג כשהם נערכים:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) { Post changedPost = dataSnapshot.getValue(Post.class); System.out.println("The updated post title is: " + changedPost.title); } @Override public void onChildRemoved(DataSnapshot dataSnapshot) {} @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get the data on a post that has changed ref.on('child_changed', (snapshot) => { const changedPost = snapshot.val(); console.log('The updated post title is ' + changedPost.title); });
הילד הוסר
האירוע child_removed
מופעל כאשר ילד מיידי מוסר. הוא משמש בדרך כלל בשילוב עם child_added
ו- child_changed
. תמונת המצב שהועברה להתקשרות חוזרת של האירוע מכילה את הנתונים של הילד שהוסר.
בדוגמה של הבלוג, אתה יכול להשתמש child_removed
כדי לרשום הודעה על הפוסט שנמחק למסוף:
Java
ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildChanged(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Post removedPost = dataSnapshot.getValue(Post.class); System.out.println("The blog post titled " + removedPost.title + " has been deleted"); } @Override public void onChildMoved(DataSnapshot dataSnapshot, String prevChildKey) {} @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
// Get a reference to our posts const ref = db.ref('server/saving-data/fireblog/posts'); // Get the data on a post that has been removed ref.on('child_removed', (snapshot) => { const deletedPost = snapshot.val(); console.log('The blog post titled \'' + deletedPost.title + '\' has been deleted'); });
ילד עבר
אירוע child_moved
משמש בעת עבודה עם נתונים מסודרים, אשר מכוסה בסעיף הבא .
ערבויות לאירועים
מסד הנתונים של Firebase נותן כמה ערבויות חשובות לגבי אירועים:
אחריות לאירועי מסד נתונים |
---|
אירועים תמיד יופעלו כאשר המדינה המקומית משתנה. |
אירועים תמיד ישקפו בסופו של דבר את המצב הנכון של הנתונים, גם במקרים שבהם פעולות מקומיות או תזמון גורמים להבדלים זמניים, כגון אובדן זמני של חיבור לרשת. |
כתבות מלקוח בודד ייכתבו תמיד לשרת וישודרו למשתמשים אחרים לפי הסדר. |
אירועי ערך מופעלים תמיד אחרונים ומובטחים שיכילו עדכונים מכל אירוע אחר שהתרחש לפני שצולמה תמונת המצב. |
מכיוון שאירועי ערך תמיד מופעלים אחרונים, הדוגמה הבאה תמיד תעבוד:
Java
final AtomicInteger count = new AtomicInteger(); ref.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // New child added, increment count int newCount = count.incrementAndGet(); System.out.println("Added " + dataSnapshot.getKey() + ", count is " + newCount); } // ... }); // The number of children will always be equal to 'count' since the value of // the dataSnapshot here will include every child_added event triggered before this point. ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { long numChildren = dataSnapshot.getChildrenCount(); System.out.println(count.get() + " == " + numChildren); } @Override public void onCancelled(DatabaseError databaseError) {} });
Node.js
let count = 0; ref.on('child_added', (snap) => { count++; console.log('added:', snap.key); }); // length will always equal count, since snap.val() will include every child_added event // triggered before this point ref.once('value', (snap) => { console.log('initial data loaded!', snap.numChildren() === count); });
ניתוק התקשרויות חוזרות
התקשרויות חוזרות מוסרות על ידי ציון סוג האירוע ופונקציית ההתקשרות להסרה, כמו הבאות:
Java
// Create and attach listener ValueEventListener listener = new ValueEventListener() { // ... }; ref.addValueEventListener(listener); // Remove listener ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);
אם העברתם הקשר של היקף ל- on()
, יש להעביר אותו בעת ניתוק ההתקשרות חזרה:
Java
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);
אם ברצונך להסיר את כל ההתקשרות חזרה במיקום מסוים, תוכל לבצע את הפעולות הבאות:
Java
// No Java equivalent, listeners must be removed individually.
Node.js
// Remove all value callbacks ref.off('value'); // Remove all callbacks of any type ref.off();
קריאת נתונים פעם אחת
במקרים מסוימים עשוי להיות שימושי להתקשר להתקשרות חוזרת פעם אחת ולאחר מכן להסיר אותה מיד. יצרנו פונקציית עוזר כדי להקל על זה:
Java
ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // ... } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
ref.once('value', (data) => { // do some stuff once });
פִּיתוֹן
# Import database module. from firebase_admin import db # Get a database reference to our posts ref = db.reference('server/saving-data/fireblog/posts') # Read the data at the posts reference (this is a blocking operation) print(ref.get())
ללכת
// Create a database client from App. client, err := app.Database(ctx) if err != nil { log.Fatalln("Error initializing database client:", err) } // Get a database reference to our posts ref := client.NewRef("server/saving-data/fireblog/posts") // Read the data at the posts reference (this is a blocking operation) var post Post if err := ref.Get(ctx, &post); err != nil { log.Fatalln("Error reading value:", err) }
שאילתת נתונים
עם שאילתות מסד נתונים של Firebase, אתה יכול לאחזר נתונים באופן סלקטיבי על סמך גורמים שונים. כדי לבנות שאילתה במסד הנתונים שלך, אתה מתחיל בציון כיצד אתה רוצה שהנתונים שלך יהיו מסודרים באמצעות אחת מפונקציות ההזמנה: orderByChild()
, orderByKey()
או orderByValue()
. לאחר מכן תוכל לשלב את אלה עם חמש שיטות אחרות לביצוע שאילתות מורכבות: limitToFirst()
, limitToLast()
, startAt()
, endAt()
ו- equalTo()
.
מכיוון שכולנו ב-Firebase חושבים שדינוזאורים הם די מגניבים, נשתמש בקטע ממסד נתונים לדוגמה של עובדות דינוזאורים כדי להדגים כיצד ניתן לבצע שאילתות לנתונים במסד הנתונים של Firebase.
{ "lambeosaurus": { "height" : 2.1, "length" : 12.5, "weight": 5000 }, "stegosaurus": { "height" : 4, "length" : 9, "weight" : 2500 } }
ניתן להזמין נתונים בשלוש דרכים: לפי מפתח צאצא , לפי מפתח או לפי ערך . שאילתת מסד נתונים בסיסית מתחילה באחת מפונקציות ההזמנה הללו, שכל אחת מהן מוסברת להלן.
הזמנה לפי מפתח צאצא מוגדר
אתה יכול להזמין צמתים לפי מפתח צאצא משותף על ידי העברת מפתח זה ל- orderByChild()
. לדוגמה, כדי לקרוא את כל הדינוזאורים מסודרים לפי גובה, אתה יכול לעשות את הפעולות הבאות:
Java
public static class Dinosaur { public int height; public int weight; public Dinosaur(int height, int weight) { // ... } } final DatabaseReference dinosaursRef = database.getReference("dinosaurs"); dinosaursRef.orderByChild("height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { Dinosaur dinosaur = dataSnapshot.getValue(Dinosaur.class); System.out.println(dataSnapshot.getKey() + " was " + dinosaur.height + " meters tall."); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
ללכת
// Dinosaur is a json-serializable type. type Dinosaur struct { Height int `json:"height"` Width int `json:"width"` } ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("%s was %d meteres tall", r.Key(), d.Height) }
כל צומת שאין לו את מפתח הילד עליו אנו מבצעים שאילתות ממוין עם הערך null
, כלומר הוא יבוא ראשון בהזמנה. לפרטים על אופן סדר הנתונים, עיין בסעיף כיצד מסודרים נתונים .
ניתן להזמין שאילתות גם לפי ילדים מקוננים עמוקים, ולא רק ילדים ברמה אחת למטה. זה שימושי אם יש לך נתונים מקוננים עמוקים כמו זה:
{ "lambeosaurus": { "dimensions": { "height" : 2.1, "length" : 12.5, "weight": 5000 } }, "stegosaurus": { "dimensions": { "height" : 4, "length" : 9, "weight" : 2500 } } }
כדי לשאול את הגובה כעת, אתה יכול להשתמש בנתיב המלא לאובייקט במקום במפתח בודד:
Java
dinosaursRef.orderByChild("dimensions/height").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { // ... } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('dimensions/height').on('child_added', (snapshot) => { console.log(snapshot.key + ' was ' + snapshot.val().height + ' meters tall'); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('dimensions/height').get() for key, val in snapshot.items(): print('{0} was {1} meters tall'.format(key, val))
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("dimensions/height").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("%s was %d meteres tall", r.Key(), d.Height) }
שאילתות יכולות להזמין רק לפי מפתח אחד בכל פעם. קריאה ל- orderByChild()
מספר פעמים באותה שאילתה זורקת שגיאה.
הזמנה לפי מפתח
אתה יכול גם להזמין צמתים לפי המפתחות שלהם באמצעות שיטת orderByKey()
. הדוגמה הבאה קוראת את כל הדינוזאורים בסדר אלפביתי:
Java
dinosaursRef.orderByKey().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().get() print(snapshot)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } snapshot := make([]Dinosaur, len(results)) for i, r := range results { var d Dinosaur if err := r.Unmarshal(&d); err != nil { log.Fatalln("Error unmarshaling result:", err) } snapshot[i] = d } fmt.Println(snapshot)
הזמנה לפי ערך
אתה יכול לסדר צמתים לפי הערך של מפתחות הצאצא שלהם באמצעות שיטת orderByValue()
. נניח שהדינוזאורים עורכים תחרות ספורט דינו ואתם עוקבים אחר התוצאות שלהם בפורמט הבא:
{ "scores": { "bruhathkayosaurus" : 55, "lambeosaurus" : 21, "linhenykus" : 80, "pterodactyl" : 93, "stegosaurus" : 5, "triceratops" : 22 } }
כדי למיין את הדינוזאורים לפי הציון שלהם, תוכל לבנות את השאילתה הבאה:
Java
DatabaseReference scoresRef = database.getReference("scores"); scoresRef.orderByValue().addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().on('value', (snapshot) => { snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
פִּיתוֹן
ref = db.reference('scores') snapshot = ref.order_by_value().get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
ללכת
ref := client.NewRef("scores") results, err := ref.OrderByValue().GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
עיין בסעיף כיצד מסודרים נתונים לקבלת הסבר על האופן שבו ממוינים ערכי null
, בוליאני, מחרוזת ואובייקט בעת שימוש orderByValue()
.
שאילתות מורכבות
כעת, לאחר שברור כיצד הנתונים שלך מסודרים, אתה יכול להשתמש בשיטות הגבלה או הטווח המתוארות להלן כדי לבנות שאילתות מורכבות יותר.
הגבלת שאילתות
השאילתות limitToFirst()
ו- limitToLast()
משמשות כדי להגדיר מספר מקסימלי של ילדים שיסונכרנו עבור התקשרות חוזרת נתונה. אם תגדיר מגבלה של 100, תקבל בהתחלה רק עד 100 אירועים child_added
. אם יש לך פחות מ-100 הודעות המאוחסנות במסד הנתונים שלך, אירוע child_added
יופעל עבור כל הודעה. עם זאת, אם יש לך יותר מ-100 הודעות, תקבל אירוע child_added
רק עבור 100 מההודעות האלה. אלו הן 100 ההודעות הראשונות שהוזמנו אם אתה משתמש limitToFirst()
או 100 ההודעות האחרונות שהסדרו אם אתה משתמש limitToLast()
. כאשר הפריטים משתנים, תקבלו אירועי child_added
עבור פריטים שנכנסים לשאילתה ואירועי child_removed
עבור פריטים שיוצאים ממנה, כך שהמספר הכולל יישאר על 100.
באמצעות מסד הנתונים של עובדות הדינוזאורים ו- orderByChild()
, אתה יכול למצוא את שני הדינוזאורים הכבדים ביותר:
Java
dinosaursRef.orderByChild("weight").limitToLast(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('weight').limitToLast(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('weight').limit_to_last(2).get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("weight").LimitToLast(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
ה-callback child_added
מופעל בדיוק פעמיים, אלא אם יש פחות משני דינוזאורים המאוחסנים במסד הנתונים. הוא גם יפוטר עבור כל דינוזאור חדש וכבד יותר שיתווסף למסד הנתונים. ב-Python, השאילתה מחזירה ישירות OrderedDict
המכיל את שני הדינוזאורים הכבדים ביותר.
באופן דומה, אתה יכול למצוא את שני הדינוזאורים הקצרים ביותר באמצעות limitToFirst()
:
Java
dinosaursRef.orderByChild("weight").limitToFirst(2).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').limitToFirst(2).on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').limit_to_first(2).get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").LimitToFirst(2).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
ה-callback child_added
מופעל בדיוק פעמיים, אלא אם יש פחות משני דינוזאורים המאוחסנים במסד הנתונים. הוא גם יפורה שוב אם אחד משני הדינוזאורים הראשונים יוסר ממאגר הנתונים, מכיוון שדינוזאור חדש יהיה כעת השני הקצר ביותר. ב-Python, השאילתה מחזירה ישירות OrderedDict
המכיל את הדינוזאורים הקצרים ביותר.
אתה יכול גם לבצע שאילתות הגבלה עם orderByValue()
. אם אתה רוצה ליצור טבלת הישגים עם 3 דינוזאורי ספורט הדינו בעלי הניקוד הגבוה ביותר, תוכל לעשות את הפעולות הבאות:
Java
scoresRef.orderByValue().limitToFirst(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println("The " + dataSnapshot.getKey() + " score is " + dataSnapshot.getValue()); } // ... });
Node.js
const scoresRef = db.ref('scores'); scoresRef.orderByValue().limitToLast(3).on('value', (snapshot) =>{ snapshot.forEach((data) => { console.log('The ' + data.key + ' dinosaur\'s score is ' + data.val()); }); });
פִּיתוֹן
scores_ref = db.reference('scores') snapshot = scores_ref.order_by_value().limit_to_last(3).get() for key, val in snapshot.items(): print('The {0} dinosaur\'s score is {1}'.format(key, val))
ללכת
ref := client.NewRef("scores") results, err := ref.OrderByValue().LimitToLast(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { var score int if err := r.Unmarshal(&score); err != nil { log.Fatalln("Error unmarshaling result:", err) } fmt.Printf("The %s dinosaur's score is %d\n", r.Key(), score) }
שאילתות טווח
שימוש startAt()
, endAt()
ו- equalTo()
מאפשר לך לבחור נקודות התחלה וסיום שרירותיות עבור השאילתות שלך. לדוגמה, אם רצית למצוא את כל הדינוזאורים שגובהם שלושה מטרים לפחות, אתה יכול לשלב orderByChild()
ו- startAt()
:
Java
dinosaursRef.orderByChild("height").startAt(3).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').startAt(3).on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').start_at(3).get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").StartAt(3).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
אתה יכול להשתמש endAt()
כדי למצוא את כל הדינוזאורים ששמם בא לפני Pterodactyl מבחינה לקסיקוגרפית:
Java
dinosaursRef.orderByKey().endAt("pterodactyl").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByKey().endAt('pterodactyl').on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().end_at('pterodactyl').get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().EndAt("pterodactyl").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
אתה יכול לשלב startAt()
ו- endAt()
כדי להגביל את שני הקצוות של השאילתה שלך. הדוגמה הבאה מוצאת את כל הדינוזאורים ששמם מתחיל באות "ב":
Java
dinosaursRef.orderByKey().startAt("b").endAt("b\uf8ff").addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
var ref = db.ref('dinosaurs'); ref.orderByKey().startAt('b').endAt('b\uf8ff').on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_key().start_at('b').end_at(u'b\uf8ff').get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByKey().StartAt("b").EndAt("b\uf8ff").GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
השיטה equalTo()
מאפשרת לך לסנן על סמך התאמות מדויקות. כמו במקרה של שאילתות טווח אחרות, הוא יופעל עבור כל צומת צאצא תואם. לדוגמה, אתה יכול להשתמש בשאילתה הבאה כדי למצוא את כל הדינוזאורים שגובהם 25 מטרים:
Java
dinosaursRef.orderByChild("height").equalTo(25).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) { System.out.println(dataSnapshot.getKey()); } // ... });
Node.js
const ref = db.ref('dinosaurs'); ref.orderByChild('height').equalTo(25).on('child_added', (snapshot) => { console.log(snapshot.key); });
פִּיתוֹן
ref = db.reference('dinosaurs') snapshot = ref.order_by_child('height').equal_to(25).get() for key in snapshot: print(key)
ללכת
ref := client.NewRef("dinosaurs") results, err := ref.OrderByChild("height").EqualTo(25).GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } for _, r := range results { fmt.Println(r.Key()) }
שאילתות טווח שימושיות גם כאשר אתה צריך לדמיין את הנתונים שלך.
מחברים את הכל ביחד
אתה יכול לשלב את כל הטכניקות הללו כדי ליצור שאילתות מורכבות. לדוגמה, אתה יכול למצוא את שמו של הדינוזאור שהוא קצר יותר מהסטגוזאורוס:
Java
dinosaursRef.child("stegosaurus").child("height").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot stegoHeightSnapshot) { Integer favoriteDinoHeight = stegoHeightSnapshot.getValue(Integer.class); Query query = dinosaursRef.orderByChild("height").endAt(favoriteDinoHeight).limitToLast(2); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Data is ordered by increasing height, so we want the first entry DataSnapshot firstChild = dataSnapshot.getChildren().iterator().next(); System.out.println("The dinosaur just shorter than the stegosaurus is: " + firstChild.getKey()); } @Override public void onCancelled(DatabaseError databaseError) { // ... } }); } @Override public void onCancelled(DatabaseError databaseError) { // ... } });
Node.js
const ref = db.ref('dinosaurs'); ref.child('stegosaurus').child('height').on('value', (stegosaurusHeightSnapshot) => { const favoriteDinoHeight = stegosaurusHeightSnapshot.val(); const queryRef = ref.orderByChild('height').endAt(favoriteDinoHeight).limitToLast(2); queryRef.on('value', (querySnapshot) => { if (querySnapshot.numChildren() === 2) { // Data is ordered by increasing height, so we want the first entry querySnapshot.forEach((dinoSnapshot) => { console.log('The dinosaur just shorter than the stegasaurus is ' + dinoSnapshot.key); // Returning true means that we will only loop through the forEach() one time return true; }); } else { console.log('The stegosaurus is the shortest dino'); } }); });
פִּיתוֹן
ref = db.reference('dinosaurs') favotire_dino_height = ref.child('stegosaurus').child('height').get() query = ref.order_by_child('height').end_at(favotire_dino_height).limit_to_last(2) snapshot = query.get() if len(snapshot) == 2: # Data is ordered by increasing height, so we want the first entry. # Second entry is stegosarus. for key in snapshot: print('The dinosaur just shorter than the stegosaurus is {0}'.format(key)) return else: print('The stegosaurus is the shortest dino')
ללכת
ref := client.NewRef("dinosaurs") var favDinoHeight int if err := ref.Child("stegosaurus").Child("height").Get(ctx, &favDinoHeight); err != nil { log.Fatalln("Error querying database:", err) } query := ref.OrderByChild("height").EndAt(favDinoHeight).LimitToLast(2) results, err := query.GetOrdered(ctx) if err != nil { log.Fatalln("Error querying database:", err) } if len(results) == 2 { // Data is ordered by increasing height, so we want the first entry. // Second entry is stegosarus. fmt.Printf("The dinosaur just shorter than the stegosaurus is %s\n", results[0].Key()) } else { fmt.Println("The stegosaurus is the shortest dino") }
כיצד מסודרים נתונים
סעיף זה מסביר כיצד הנתונים שלך מסודרים בעת שימוש בכל אחת מארבע פונקציות ההזמנה.
orderByChild
בעת שימוש orderByChild()
, הנתונים המכילים את מפתח הצאצא שצוין מסודרים באופן הבא:
- ילדים עם ערך
null
עבור מפתח הצאצא שצוין קודמים. - ילדים עם הערך של
false
עבור מפתח הצאצא שצוין מגיעים לאחר מכן. אם למספר ילדים יש ערך שלfalse
, הם ממוינים בלקסיקוגרפית לפי מפתח. - ילדים עם הערך של
true
עבור מפתח הצאצא שצוין מגיעים לאחר מכן. אם למספר ילדים יש ערך שלtrue
, הם ממוינים בלקסיקוגרפית לפי מפתח. - ילדים עם ערך מספרי מגיעים אחר כך, ממוינים בסדר עולה. אם למספר ילדים יש ערך מספרי זהה עבור צומת הצאצא שצוין, הם ממוינים לפי מפתח.
- מחרוזות באות אחרי מספרים, וממוינות בלקסיקוגרפית בסדר עולה. אם למספר ילדים יש ערך זהה עבור צומת הילד שצוין, הם מסודרים בלקסיקוגרפית לפי מפתח.
- אובייקטים מגיעים אחרונים, וממוינים בצורה לקסיקוגרפית לפי מפתח בסדר עולה.
orderByKey
בעת שימוש orderByKey()
למיון הנתונים שלך, הנתונים מוחזרים בסדר עולה לפי מפתח באופן הבא. זכור שמפתחות יכולים להיות רק מחרוזות.
- ילדים עם מפתח שניתן לנתח כמספר שלם של 32 סיביות מגיעים ראשונים, ממוינים בסדר עולה.
- ילדים עם ערך מחרוזת כמפתח מגיעים אחר כך, ממוינים בלקסיוגרפית בסדר עולה.
orderByValue
בעת שימוש ב- orderByValue()
, ילדים מסודרים לפי הערך שלהם. קריטריוני ההזמנה זהים ל- orderByChild()
, אלא שהערך של הצומת משמש במקום הערך של מפתח צאצא שצוין.