يغطي هذا المستند أساسيات استرداد بيانات قاعدة البيانات ، وكيفية ترتيب البيانات ، وكيفية إجراء استعلامات بسيطة على البيانات. يتم تنفيذ استرداد البيانات في Admin SDK بشكل مختلف قليلاً عبر لغات البرمجة المختلفة.
- المستمعون غير المتزامنون: يتم استرداد البيانات المخزنة في قاعدة بيانات Firebase Realtime عن طريق إرفاق مستمع غير متزامن بمرجع قاعدة بيانات. يتم تشغيل المستمع مرة واحدة للحالة الأولية للبيانات ومرة أخرى في أي وقت تتغير فيه البيانات. قد يتلقى مستمع الحدث عدة أنواع مختلفة من الأحداث . يتم دعم هذا الوضع لاسترداد البيانات في Java و Node.js و Python Admin SDKs.
- قراءة الحظر: يتم استرداد البيانات المخزنة في قاعدة بيانات Firebase Realtime عن طريق استدعاء طريقة الحظر في مرجع قاعدة البيانات ، والتي تُعيد البيانات المخزنة في المرجع. كل طريقة استدعاء هي عملية لمرة واحدة. هذا يعني أن SDK لا تسجل أي عمليات استرجاع تستمع إلى تحديثات البيانات اللاحقة. يتم دعم هذا النموذج لاسترداد البيانات في حزم SDK لـ Python و Go Admin.
ابدء
دعنا نعيد النظر في مثال التدوين من المقالة السابقة لفهم كيفية قراءة البيانات من قاعدة بيانات 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 = 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 ، تتلقى وظيفة رد الاتصال DataSnapshot
، وهي لقطة من البيانات. اللقطة هي صورة للبيانات في مرجع قاعدة بيانات معين في نقطة زمنية واحدة. يؤدي استدعاء val()
/ getValue()
في لقطة ما إلى إرجاع تمثيل كائن خاص بلغة معينة للبيانات. في حالة عدم وجود بيانات في موقع المرجع ، تكون قيمة اللقطة null
. تقوم طريقة get()
في بايثون بإرجاع تمثيل Python للبيانات مباشرة. تقوم وظيفة Get()
في Go بإلغاء تنظيم البيانات في بنية بيانات معينة.
لاحظ أننا استخدمنا نوع حدث 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
مرتين بالضبط ، ما لم يكن هناك أقل من اثنين من الديناصورات المخزنة في قاعدة البيانات. سيتم إطلاقه أيضًا لكل ديناصور جديد أثقل يتم إضافته إلى قاعدة البيانات. في Python ، يعرض الاستعلام أمر 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
مرتين بالضبط ، ما لم يكن هناك أقل من اثنين من الديناصورات المخزنة في قاعدة البيانات. سيتم إطلاقه أيضًا مرة أخرى إذا تمت إزالة أحد الديناصورات الأولين من قاعدة البيانات ، حيث سيكون الديناصور الجديد الآن ثاني أقصر الديناصورات. في Python ، يقوم الاستعلام بإرجاع أمر OrderedDict
الذي يحتوي على أقصر الديناصورات.
يمكنك أيضًا إجراء استعلامات محدودة باستخدام orderByValue()
. إذا كنت ترغب في إنشاء لوحة ليدربورد تحتوي على أعلى 3 ديناصورات رياضية سجلت أعلى الدرجات ، فيمكنك القيام بما يلي:
جافا
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()
للعثور على جميع الديناصورات التي تأتي أسماؤها قبل معجم الزاحف المجنح:
جافا
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()) }
استعلامات النطاق مفيدة أيضًا عندما تحتاج إلى ترقيم بياناتك.
ضع كل شيء معا
يمكنك دمج كل هذه الأساليب لإنشاء استعلامات معقدة. على سبيل المثال ، يمكنك العثور على اسم الديناصور الأقصر من Stegosaurus:
جافا
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()
، يتم ترتيب البيانات التي تحتوي على المفتاح الفرعي المحدد على النحو التالي:
- الأطفال الذين لديهم قيمة
null
للمفتاح الفرعي المحدد يأتون أولاً. - يأتي بعد ذلك الأطفال الذين لديهم قيمة
false
للمفتاح الفرعي المحدد. إذا كان هناك العديد من الأطفال الذين لديهم قيمةfalse
، فسيتم فرزهم حسب المعجم حسب المفتاح. - يأتي بعد ذلك الأطفال الذين لديهم قيمة
true
للمفتاح الفرعي المحدد. إذا كان للعديد من الأطفال قيمةtrue
، فسيتم فرزهم حسب المعجم حسب المفتاح. - يأتي الأطفال ذوو القيمة الرقمية بعد ذلك ، ويتم فرزهم بترتيب تصاعدي. إذا كان لدى العديد من الأطفال نفس القيمة العددية للعقدة الفرعية المحددة ، فسيتم فرزهم حسب المفتاح.
- تأتي السلاسل بعد الأرقام ، ويتم ترتيبها حسب المعجم بترتيب تصاعدي. إذا كان لدى العديد من الأطفال نفس القيمة للعقدة الفرعية المحددة ، فسيتم ترتيبهم حسب المعجم حسب المفتاح.
- تأتي الكائنات أخيرًا ، ويتم ترتيبها حسب المعجم حسب المفتاح بترتيب تصاعدي.
الطلب
عند استخدام orderByKey()
لفرز بياناتك ، يتم إرجاع البيانات بترتيب تصاعدي حسب المفتاح على النحو التالي. ضع في اعتبارك أن المفاتيح يمكن أن تكون سلاسل فقط.
- الأطفال الذين لديهم مفتاح يمكن تحليله كعدد صحيح 32 بت يأتون أولاً ، ويتم فرزهم بترتيب تصاعدي.
- يأتي بعد ذلك الأطفال الذين لديهم قيمة سلسلة كمفتاح لهم ، ويتم فرزهم حسب المعجم بترتيب تصاعدي.
ترتيب حسب القيمة
عند استخدام orderByValue()
، يتم ترتيب الأطفال حسب قيمتها. معايير الترتيب هي نفسها الموجودة في orderByChild()
، باستثناء استخدام قيمة العقدة بدلاً من قيمة المفتاح الفرعي المحدد.