משחזר נתונים

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

  1. המאזינים אסינכרוני: נתונים מאוחסנים במסד נתונים בזמן אמת Firebase מאוחזר על ידי צירוף של המאזין אסינכרוני כדי הפנייה למאגר הנתונים. המאזין מופעל פעם אחת עבור המצב הראשוני של הנתונים ושוב בכל פעם שהנתונים משתנים. האזנה לאירוע עשוי לקבל מספר שונה סוגים של אירועים . מצב זה של אחזור נתונים נתמך ב- Java, Node.js ו- SDK Admin של מנהלי מערכת.
  2. חסימת כניסות: נתונים מאוחסנים במסד נתונים בזמן אמת Firebase מאוחזר על ידי העלאת שיטה לחסימת על הפנייה למאגר הנתונים, אשר מחזירה את הנתונים המאוחסנים על הפניה. כל קריאת שיטה היא פעולה חד פעמית. פירוש הדבר ש- SDK אינו רושם שיחות חוזרות שמאזינות לעדכוני הנתונים הבאים. מודל זה של אחזור נתונים נתמך ב- Python ו- Go Admin SDK.

מתחילים

בואו ונבקר בדוגמת הבלוגים מהמאמר הקודם כדי להבין כיצד לקרוא נתונים ממסד נתונים של Firebase. נזכיר כי רשומות בבלוג ביישום לדוגמה מאוחסנים במסד הנתונים URL https://docs-examples.firebaseio.com/server/saving-data/fireblog/posts.json . כדי לקרוא את נתוני הפוסט שלך, אתה יכול לעשות את הפעולות הבאות:

ג'אווה
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 = admin.database();
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() הפונקציה עבור unmarshals הנתונים לתוך מבנה נתונים נתון.

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

קרא סוגי אירועים ב- Java ו- Node.js

ערך

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

ילד נוסף

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

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

ג'אווה
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 לקרוא נתונים מעודכנים על רשומות בבלוג כשהם ערוכים:

ג'אווה
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 להיכנס התראה על הפוסט שנמחק למסוף:

ג'אווה
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 מספק כמה ערבויות חשובות ביחס לאירועים:

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

מכיוון שאירועי ערך מופעלים תמיד אחרונים, הדוגמה הבאה תמיד תפעל:

ג'אווה
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);
});

ניתוק שיחות חוזרות

שיחות חוזרות מוסרות על ידי ציון סוג האירוע ופונקציית החזרת המסר, כמו:

ג'אווה
// Create and attach listener
ValueEventListener listener = new ValueEventListener() {
    // ...
};
ref.addValueEventListener(listener);

// Remove listener
ref.removeEventListener(listener);
Node.js
ref.off('value', originalCallback);

אם עברת בהקשר להיקף לתוך on() , עליה להיות מתועל כאשר ניתוק ההתקשרות:

ג'אווה
// Not applicable for Java
Node.js
ref.off('value', originalCallback, ctx);

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

ג'אווה
// 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();

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

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

ג'אווה
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() . לדוגמה, כדי לקרוא את כל הדינוזאורים לפי סדר גובה, אתה יכול לעשות את הפעולות הבאות:

ג'אווה
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
    }
  }
}

לשאילתת הגובה כעת, תוכל להשתמש בנתיב המלא לאובייקט ולא במקש יחיד:

ג'אווה
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() שיטה. הדוגמה הבאה קוראת את כל הדינוזאורים בסדר אלפביתי:

ג'אווה
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
  }
}

כדי למיין את הדינוזאורים לפי הציון שלהם, תוכל לבנות את השאילתה הבאה:

ג'אווה
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() , אתה יכול למצוא את שני דינוזאורים כבדים:

ג'אווה
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())
}

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

באופן דומה, ניתן למצוא את שני דינוזאורים קצרים באמצעות limitToFirst() :

ג'אווה
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())
}

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

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

ג'אווה
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() :

ג'אווה
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 lexicographically:

ג'אווה
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() להגביל בשני הקצוות של השאילתה שלך. הדוגמה הבאה מוצאת את כל הדינוזאורים ששמם מתחיל באות "b":

ג'אווה
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 מטר:

ג'אווה
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())
}

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

מחברים את הכל ביחד

ניתן לשלב את כל הטכניקות הללו כדי ליצור שאילתות מורכבות. לדוגמה, תוכלו למצוא את שמו של הדינוזאור שהוא קצר יותר מסטגוזאור:

ג'אווה
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() , נתונים המכילים את מפתח הילד שצוין הורה כדלקמן:

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

orderByKey

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

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

orderByValue

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