משחזר נתונים

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

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

מתחילים

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

ג'אווה
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() , למעט הערך של הצומת משמש במקום הערך של מפתח הבן שצוין.