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

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

لقراءة البيانات أو كتابتها في قاعدة البيانات، تحتاج إلى مثيل من 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');

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

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

لفلترة البيانات، يمكنك الجمع بين أيّ من طُرق الحدّ أو النطاق وطريقة order-by عند إنشاء طلب بحث.

الطريقة الاستخدام
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() على أي أدوات معالجة بيانات تابعة لإزالة وظيفة معاودة الاتصال.

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