التعامل مع قوائم البيانات على الويب

الحصول على مرجع قاعدة بيانات

لقراءة البيانات من قاعدة البيانات أو كتابتها فيها، تحتاج إلى مثيل من firebase.database.Reference:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

قراءة القوائم وكتابتها

إضافة بيانات إلى قائمة

استخدِم طريقة push() لإضافة البيانات إلى قائمة في التطبيقات المتعددة المستخدمين. تنشئ طريقة push() مفتاحًا فريدًا في كل مرة تتم فيها إضافة عنصر ثانوي جديد إلى مرجع Firebase المحدّد. باستخدام هذه المفاتيح التي يتم إنشاؤها تلقائيًا لكل عنصر جديد في القائمة، يمكن لعدة عملاء إضافة عناصر ثانوية إلى الموقع نفسه في الوقت نفسه بدون حدوث تعارضات في الكتابة. يستند المفتاح الفريد الذي تم إنشاؤه بواسطة push() إلى طابع زمني، لذا يتم ترتيب عناصر القائمة تلقائيًا بترتيب زمني.

يمكنك استخدام المرجع للبيانات الجديدة التي تعرضها طريقة push() للحصول على قيمة المفتاح الذي تم إنشاؤه تلقائيًا للعنصر الثانوي أو ضبط بيانات العنصر الثانوي. تحتوي السمة .key لمرجع push() على المفتاح الذي تم إنشاؤه تلقائيًا.

يمكنك استخدام هذه المفاتيح التي يتم إنشاؤها تلقائيًا لتبسيط تسوية بنية بياناتك. لمزيد من المعلومات، اطّلِع على مثال توزيع البيانات الموسَّع .

على سبيل المثال، يمكن استخدام push() لإضافة مشاركة جديدة إلى قائمة مشاركات في تطبيق اجتماعي:

Web

import { getDatabase, ref, push, set } from "firebase/database";

// Create a new post reference with an auto-generated id
const db = getDatabase();
const postListRef = ref(db, 'posts');
const newPostRef = push(postListRef);
set(newPostRef, {
    // ...
});

Web

// Create a new post reference with an auto-generated id
var postListRef = firebase.database().ref('posts');
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

الاستماع إلى أحداث العناصر الثانوية

يتم تشغيل أحداث العناصر الثانوية استجابةً لعمليات معيّنة تحدث للعناصر الثانوية لعقدة من عملية، مثل إضافة عنصر ثانوي جديد من خلال طريقة push() أو تعديل عنصر ثانوي من خلال طريقة update().

الحدث الاستخدام المعتاد
child_added استرداد قوائم العناصر أو الاستماع إلى الإضافات إلى قائمة العناصر يتم تشغيل هذا الحدث مرة واحدة لكل عنصر ثانوي حالي، ثم مرة أخرى في كل مرة تتم فيها إضافة عنصر ثانوي جديد إلى المسار المحدّد. يتم تمرير لقطة تحتوي على بيانات العنصر الثانوي الجديد إلى المستمع.
child_changed الاستماع إلى التغييرات التي تطرأ على العناصر في قائمة يتم تشغيل هذا الحدث في أي وقت يتم فيه تعديل عقدة عنصر ثانوي. ويشمل ذلك أي تعديلات على العناصر الفرعية لعقدة العنصر الثانوي. تحتوي اللقطة التي تم تمريرها إلى متتبِّع الأحداث على البيانات المعدَّلة للعنصر الثانوي.
child_removed الاستماع إلى العناصر التي تتم إزالتها من قائمة يتم تشغيل هذا الحدث عند إزالة عنصر ثانوي مباشر.تحتوي اللقطة التي تم تمريرها إلى كتلة معاودة الاتصال على بيانات العنصر الثانوي الذي تمت إزالته.
child_moved الاستماع إلى التغييرات التي تطرأ على ترتيب العناصر في قائمة مرتبة تتبع أحداث child_moved دائمًا حدث child_changed الذي تسبّب في تغيير ترتيب العنصر تغيير (استنادًا إلى طريقة الترتيب حسب الحالية).

يمكن أن يكون كل من هذه الأحداث مفيدًا للاستماع إلى التغييرات التي تطرأ على عقدة معيّنة في قاعدة بيانات. على سبيل المثال، قد يستخدم تطبيق تدوين اجتماعي هذه الطرق معًا لمراقبة النشاط في التعليقات على مشاركة، كما هو موضّح أدناه:

Web

import { getDatabase, ref, onChildAdded, onChildChanged, onChildRemoved } from "firebase/database";

const db = getDatabase();
const commentsRef = ref(db, 'post-comments/' + postId);
onChildAdded(commentsRef, (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

onChildChanged(commentsRef, (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

onChildRemoved(commentsRef, (data) => {
  deleteComment(postElement, data.key);
});

Web

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', (data) => {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', (data) => {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', (data) => {
  deleteComment(postElement, data.key);
});

الاستماع إلى أحداث القيمة

على الرغم من أنّ الاستماع إلى أحداث العناصر الثانوية هو الطريقة المقترَحة لقراءة قوائم البيانات، هناك حالات يكون فيها الاستماع إلى أحداث القيمة في مرجع قائمة مفيدًا.

سيؤدي إرفاق مراقب value بقائمة بيانات إلى عرض القائمة الكاملة للبيانات كلقطة واحدة يمكنك بعد ذلك تكرارها للوصول إلى العناصر الثانوية الفردية.

حتى إذا كان هناك تطابق واحد فقط لطلب البحث، تظل اللقطة قائمة، ولكنها تحتوي على عنصر واحد فقط. للوصول إلى العنصر، عليك تكرار النتيجة:

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const dbRef = ref(db, '/a/b/c');

onValue(dbRef, (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    const childKey = childSnapshot.key;
    const childData = childSnapshot.val();
    // ...
  });
}, {
  onlyOnce: true
});

Web

ref.once('value', (snapshot) => {
  snapshot.forEach((childSnapshot) => {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

يمكن أن يكون هذا النمط مفيدًا عندما تريد جلب جميع العناصر الثانوية لقائمة في عملية واحدة، بدلاً من الاستماع إلى أحداث العناصر الثانوية الإضافية التي تمت إضافتها.

فرز البيانات وتصفيتها

يمكنك استخدام فئة Realtime Database Query لاسترداد البيانات التي تم فرزها حسب المفتاح أو القيمة أو قيمة عنصر ثانوي. يمكنك أيضًا فلترة النتيجة التي تم فرزها لعدد معيّن من النتائج أو نطاق من المفاتيح أو القيم.

فرز البيانات

لاسترداد البيانات التي تم فرزها، ابدأ بتحديد إحدى طرق الترتيب حسب لتحديد كيفية ترتيب النتائج:

الطريقة الاستخدام
orderByChild() ترتيب النتائج حسب قيمة مفتاح عنصر ثانوي محدّد أو مسار عنصر ثانوي متداخل
orderByKey() ترتيب النتائج حسب مفاتيح العناصر الثانوية
orderByValue() ترتيب النتائج حسب قيم العناصر الثانوية

يمكنك استخدام طريقة واحدة فقط للترتيب حسب في كل مرة. يؤدي استدعاء طريقة الترتيب حسب عدة مرات في طلب البحث نفسه إلى ظهور خطأ.

يوضّح المثال التالي كيفية استرداد قائمة بأهم مشاركات المستخدم التي تم فرزها حسب عدد النجوم:

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const myUserId = auth.currentUser.uid;
const topUserPostsRef = query(ref(db, 'user-posts/' + myUserId), orderByChild('starCount'));

Web

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' + myUserId).orderByChild('starCount');

يحدّد هذا المثال طلب بحث، وعند دمجه مع مستمع عنصر ثانوي تتم مزامنة العميل مع منشورات المستخدم من المسار في قاعدة البيانات استنادًا إلى رقم تعريف المستخدم، ويتم ترتيبها حسب عدد النجوم التي حصلت عليها كل مشاركة. تُعرف هذه التقنية لاستخدام أرقام التعريف كمفاتيح فهرس باسم توزيع البيانات الموسَّع، ويمكنك قراءة المزيد عنها في مقالة تنظيم قاعدة البيانات.

يحدّد استدعاء طريقة orderByChild() مفتاح العنصر الثانوي الذي يتم ترتيب النتائج حسبه. في هذه الحالة، يتم فرز المشاركات حسب قيمة العنصر الثانوي الخاص بها "starCount". يمكن أيضًا ترتيب طلبات البحث حسب العناصر الثانوية المتداخلة، في حال توفّر بيانات تبدو على النحو التالي:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

في هذه الحالة، يمكننا ترتيب عناصر القائمة حسب القيم المتداخلة ضمن المفتاح metrics من خلال تحديد المسار النسبي للعنصر الثانوي المتداخل في استدعاء orderByChild().

Web

import { getDatabase, ref, query, orderByChild } from "firebase/database";

const db = getDatabase();
const mostViewedPosts = query(ref(db, 'posts'), orderByChild('metrics/views'));

Web

var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

لمزيد من المعلومات حول كيفية ترتيب أنواع البيانات الأخرى، اطّلِع على كيفية ترتيب بيانات طلب البحث.

تصفية البيانات

لتصفية البيانات، يمكنك دمج أي من طرق الحد أو النطاق مع طريقة الترتيب حسب عند إنشاء طلب بحث.

الطريقة الاستخدام
limitToFirst() يضبط الحد الأقصى لعدد العناصر التي سيتم عرضها من بداية الـ قائمة المرتبة للنتائج.
limitToLast() يضبط الحد الأقصى لعدد العناصر التي سيتم عرضها من نهاية القائمة المرتبة للنتائج.
startAt() يعرض العناصر الأكبر من المفتاح أو القيمة المحدّدة أو المساوية لها، استنادًا إلى طريقة الترتيب حسب التي تم اختيارها.
startAfter() يعرض العناصر الأكبر من المفتاح أو القيمة المحدّدة استنادًا إلى طريقة الترتيب حسب التي تم اختيارها.
endAt() يعرض العناصر الأصغر من المفتاح أو القيمة المحدّدة أو المساوية لها، استنادًا إلى طريقة الترتيب حسب التي تم اختيارها.
endBefore() يعرض العناصر الأصغر من المفتاح أو القيمة المحدّدة استنادًا إلى طريقة الترتيب حسب التي تم اختيارها.
equalTo() يعرض العناصر التي تساوي المفتاح أو القيمة المحدّدة، استنادًا إلى طريقة الترتيب حسب التي تم اختيارها.

على عكس طرق الترتيب حسب، يمكنك دمج عدة دوال للحد أو النطاق. على سبيل المثال، يمكنك دمج الطريقتَين startAt() وendAt() لحصر النتائج في نطاق معيّن من القيم.

الحد من عدد النتائج

يمكنك استخدام الطريقتَين limitToFirst() وlimitToLast() لضبط الحد الأقصى لعدد العناصر الثانوية التي تتم مزامنتها لحدث معيّن. على سبيل المثال، إذا استخدمت limitToFirst() لضبط حد يبلغ 100، لن تتلقّى في البداية سوى ما يصل إلى 100 حدث child_added. إذا كان لديك أقل من 100 عنصر مخزّن في قاعدة بيانات Firebase، يتم تشغيل حدث child_added لكل عنصر.

عندما تتغير العناصر، تتلقّى أحداث child_added للعناصر التي تدخل طلب البحث وأحداث child_removed للعناصر التي تخرج منه، بحيث يظل العدد الإجمالي 100.

يوضّح المثال التالي كيف يحدّد تطبيق تدوين تجريبي طلب بحث لاسترداد قائمة بأحدث 100 مشاركة لجميع المستخدمين:

Web

import { getDatabase, ref, query, limitToLast } from "firebase/database";

const db = getDatabase();
const recentPostsRef = query(ref(db, 'posts'), limitToLast(100));

Web

var recentPostsRef = firebase.database().ref('posts').limitToLast(100);

يحدّد هذا المثال طلب بحث فقط، ولتتم مزامنة البيانات فعليًا، يجب أن يكون هناك متتبِّع مرفق.

الفلترة حسب المفتاح أو القيمة

يمكنك استخدام startAt() وstartAfter() وendAt() وendBefore() وequalTo() لاختيار نقاط عشوائية للبدء والانتهاء والتطابق لطلبات البحث. يمكن أن يكون ذلك مفيدًا لتقسيم البيانات إلى صفحات أو العثور على عناصر تحتوي على عناصر ثانوية لها قيمة معيّنة.

كيفية ترتيب بيانات طلب البحث

يوضّح هذا القسم كيفية فرز البيانات حسب كل طريقة من طرق الترتيب حسب في فئة Query.

orderByChild

عند استخدام orderByChild()، يتم ترتيب البيانات التي تحتوي على مفتاح العنصر الثانوي المحدّد على النحو التالي:

  1. تظهر أولاً العناصر الثانوية التي لها قيمة null لمفتاح العنصر الثانوي المحدّد.
  2. تظهر بعد ذلك العناصر الثانوية التي لها قيمة false لمفتاح العنصر الثانوي المحدّد تأتي بعد ذلك. إذا كان لدى عدة عناصر ثانوية قيمة false، يتم فرزها حسب الترتيب المعجمي حسب المفتاح.
  3. تظهر بعد ذلك العناصر الثانوية التي لها قيمة true لمفتاح العنصر الثانوي المحدّد تأتي بعد ذلك. إذا كان لدى عدة عناصر ثانوية قيمة true، يتم فرزها حسب الترتيب المعجمي حسب المفتاح.
  4. تظهر بعد ذلك العناصر الثانوية التي لها قيمة رقمية، ويتم فرزها بترتيب تصاعدي. إذا كان لدى عدة عناصر ثانوية القيمة الرقمية نفسها لعقدة العنصر الثانوي المحدّدة، يتم فرزها حسب المفتاح.
  5. تظهر السلاسل بعد الأرقام ويتم فرزها حسب الترتيب المعجمي بترتيب تصاعدي. إذا كان لدى عدة عناصر ثانوية القيمة نفسها لعقدة العنصر الثانوي المحدّدة ، يتم ترتيبها حسب الترتيب المعجمي حسب المفتاح.
  6. تظهر الكائنات أخيرًا ويتم فرزها حسب الترتيب المعجمي حسب المفتاح بترتيب تصاعدي.

orderByKey

عند استخدام orderByKey() لفرز بياناتك، يتم عرض البيانات بترتيب تصاعدي حسب المفتاح.

  1. تظهر أولاً العناصر الثانوية التي يمكن تحليل مفتاحها كعدد صحيح 32 بت، ويتم فرزها بترتيب تصاعدي.
  2. تظهر بعد ذلك العناصر الثانوية التي لها قيمة سلسلة كمفتاح، ويتم فرزها حسب الترتيب المعجمي بترتيب تصاعدي.

orderByValue

عند استخدام orderByValue()، يتم ترتيب العناصر الثانوية حسب قيمتها. تكون معايير الترتيب هي نفسها في orderByChild()، باستثناء أنّه يتم استخدام قيمة العقدة بدلاً من قيمة مفتاح عنصر ثانوي محدّد.

إزالة المستمعين

تتم إزالة عمليات معاودة الاتصال من خلال استدعاء طريقة off() في مرجع قاعدة بيانات Firebase.

يمكنك إزالة متتبِّع واحد من خلال ضبطه كمعلَمة إلى off(). يؤدي استدعاء off() في الموقع بدون أي وسيطات إلى إزالة جميع المستمعين في هذا الموقع.

لا يؤدي استدعاء off() في مستمع رئيسي إلى إزالة المتتبعين المسجّلين في عقد العناصر الثانوية تلقائيًا، بل يجب أيضًا استدعاء off() في أي متتبعين للعناصر الثانوية لإزالة معاودة الاتصال.

الخطوات التالية