قراءة البيانات وكتابتها على الويب

(اختياري) إنشاء نموذج أولي واختباره باستخدام "Firebase Local Emulator Suite"

قبل الحديث عن كيفية قراءة تطبيقك لبيانات Realtime Database وكتابتها فيه، نريد أن نقدّم لك مجموعة من الأدوات التي يمكنك استخدامها لإنشاء نماذج أولية لوظائف Realtime Database واختبارها: Firebase Local Emulator Suite. إذا كنت تختبر نماذج بيانات مختلفة أو تعمل على تحسين قواعد الأمان أو تبحث عن الطريقة الأكثر فعالية من حيث التكلفة للتفاعل مع الخلفية، قد يكون من المفيد أن تتمكّن من العمل على الجهاز بدون نشر الخدمات المباشرة.

ويُعد محاكي Realtime Database جزءًا من Local Emulator Suite، وهو للتطبيق التفاعل مع محتوى قاعدة البيانات التي تمّت محاكاتها وإعداداتها، بالإضافة إلى موارد المشروع التي تمت محاكاتها (الدوال وقواعد البيانات الأخرى وقواعد الأمان).

يتضمّن استخدام محاكي Realtime Database بضع خطوات فقط:

  1. إضافة سطر من الرمز إلى إعدادات اختبار تطبيقك للاتصال بالمحاكي.
  2. من جذر دليل المشروع المحلي، مع تشغيل firebase emulators:start.
  3. إجراء الاتصالات من رمز النموذج الأولي لتطبيقك باستخدام النظام الأساسي Realtime Database حزمة SDK كالمعتاد أو تستخدم Realtime Database REST API.

تتوفّر جولة تفصيلية تشمل Realtime Database وCloud Functions. ومن المفترض أيضًا أن تُلقي نظرة على مقدمة Local Emulator Suite.

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

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

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

كتابة البيانات

يتناول هذا المستند أساسيات استرداد البيانات وكيفية الترتيب والتصفية بيانات Firebase.

يتم استرداد بيانات Firebase من خلال إرفاق مستمع غير متزامن firebase.database.Reference يتم تشغيل المستمع مرة واحدة الحالة الأولية للبيانات ومرة أخرى في أي وقت تتغير فيه البيانات.

عمليات الكتابة الأساسية

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

Web

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

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

يؤدي استخدام set() إلى استبدال البيانات في الموقع الجغرافي المحدّد، بما في ذلك أي عناصر فرعية. العُقد.

قراءة البيانات

الاطّلاع على الأحداث القيّمة

لقراءة البيانات في مسار والاستماع إلى التغييرات، استخدِم onValue() للتتبّع. أحداث. يمكنك استخدام هذا الحدث لقراءة لقطات ثابتة للمحتوى في المسار المحدد، لأنها كانت موجودة وقت الحدث. هذه الطريقة يتم تشغيلها مرة واحدة عندما يتم توصيل المستمع ومرة أخرى في كل مرة تتغير فيها البيانات، بما فيها الأطفال. يحصل معاودة الاتصال بالحدث على نبذة تحتوي على جميع البيانات في هذا الموقع، بما في ذلك البيانات الفرعية. إذا لم تكن هناك بيانات، ستعرض اللقطة false عند طلب exists() وnull عند طلب val() عليه.

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

Web

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

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

يتلقّى المستمع snapshot الذي يحتوي على البيانات على النطاق الموقع في قاعدة البيانات وقت الحدث. يمكنك استرداد البيانات في snapshot باستخدام الطريقة val().

قراءة البيانات مرة واحدة

قراءة البيانات مرة واحدة باستخدام get()

تم تصميم حزمة SDK لإدارة التفاعلات مع خوادم قواعد البيانات سواء كان تطبيقك متصلاً بالإنترنت أو غير متصل.

بشكل عام، عليك استخدام تقنيات أحداث القيم الموضّحة أعلاه لقراءة البيانات من أجل تلقّي إشعارات بشأن التعديلات التي يتم إجراؤها على البيانات من الخلفية. المستمع أساليب تقلل من الاستخدام والفوترة، ويتم تحسينها لمنح المستخدمين أفضل تجربة عند استخدام الإنترنت وبلا اتصال بالإنترنت.

إذا كنت بحاجة إلى البيانات مرة واحدة فقط، يمكنك استخدام get() للحصول على نبذة بيانات من قاعدة البيانات. في حال تعذُّر إرجاع الخادم على get() لأي سبب فسيتم فحص العميل لذاكرة التخزين المؤقت على الجهاز وعرض رسالة خطأ إذا لم يتم العثور على القيمة حتى الآن.

فالاستخدام غير الضروري لـ get() قد يزيد من استخدام معدل نقل البيانات ويؤدي إلى فقدان الأداء، والذي يمكن منعه باستخدام أداة معالجة الأحداث في الوقت الفعلي كما هو موضح أعلاه.

Web

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

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

قراءة البيانات مرة واحدة مع مراقب

في بعض الحالات، قد تحتاج إلى عرض القيمة من ذاكرة التخزين المؤقت المحلية على الفور، بدلاً من البحث عن أي قيمة محدَّثة على الخادم. في تلك في الحالات، يمكنك استخدام once() للحصول على البيانات من ذاكرة التخزين المؤقت على القرص المحلي فورًا.

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

Web

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

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

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

تعديل البيانات أو حذفها

تعديل حقول معيّنة

للكتابة في الوقت نفسه إلى عناصر ثانوية محددة من عقدة دون استبدال القيم الأخرى العُقد الثانوية، استخدم الطريقة update().

عند استدعاء update()، يمكنك تعديل القيم الفرعية ذات المستوى الأدنى من خلال تحديد مسار للمفتاح. إذا تم تخزين البيانات في مواقع متعددة لتوسيع نطاقها بشكل أفضل، يمكنك تحديث جميع حالات هذه البيانات باستخدام توزيع البيانات.

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

Web

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

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

يستخدم هذا المثال push() لإنشاء مشاركة في العقدة التي تحتوي على مشاركات لجميع المستخدمين في /posts/$postid واسترداد المفتاح في الوقت نفسه. يمكن للمفتاح ثم استخدامها لإنشاء إدخال ثانٍ في ملف تعريف المشاركات في /user-posts/$userid/$postid.

باستخدام هذه المسارات، يمكنك إجراء تحديثات متزامنة للعديد من المواقع في شجرة JSON مع استدعاء واحد إلى update()، مثل كيف يظهر هذا المثال تنشئ المشاركة الجديدة في كلا الموقعين. التحديثات المتزامنة التي تم إجراؤها بهذه الطريقة بسيطة: إما أن تنجح جميع التحديثات أو أن جميع التحديثات تفشل.

إضافة معاودة اتصال مكتملة

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

Web

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

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

حذف البيانات

إنّ أبسط طريقة لحذف البيانات هي استدعاء remove() باستخدام مرجع إلى موقع تلك البيانات.

يمكنك أيضًا الحذف من خلال تحديد null كقيمة لعملية كتابة أخرى. عملية مثل set() أو update(). يمكنك استخدام هذا الأسلوب مع update() لحذف عدة عناصر فرعية في طلب بيانات واحد من واجهة برمجة التطبيقات.

تلقّي Promise

لمعرفة وقت التزام بياناتك بخادم Firebase Realtime Database، عليك هل يمكن استخدام Promise يمكن أن يعرض كل من set() وupdate() Promise يمكنك استخدامه لمعرفة وقت تثبيت عملية الكتابة في قاعدة البيانات.

فصل المستمعين

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

يمكنك إزالة مستمع واحد من خلال تمريره كمَعلمة إلى off(). سيؤدي الاتصال بالرقم off() في الموقع الجغرافي بدون وسيطات إلى إزالة جميع المستمعين في ذلك الوقت. الموقع.

لا يؤدي الاتصال بـ "off()" على مستمِع أحد الوالدَين إزالة المستمعين المسجَّلين في العُقد الفرعية تلقائيًا يجب أيضًا استدعاء off() على أي أدوات استماع تابعة للأطفال لإزالة رد الاتصال.

حفظ البيانات كمعاملات

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

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

Web

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

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

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

الإضافات البسيطة من جهة الخادم

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

Web

function addStar(uid, key) {
  import { getDatabase, increment, ref, update } from "firebase/database";
  const dbRef = ref(getDatabase());

  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = increment(1);
  update(dbRef, updates);
}

Web

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

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

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

العمل باستخدام البيانات بلا اتصال بالإنترنت

إذا فقد أحد البرامج اتصاله بالشبكة، سيستمر التطبيق في العمل. بشكل صحيح.

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

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

بعد إعادة الاتصال، يتلقّى تطبيقك المجموعة المناسبة من الأحداث حتى تتم مزامنة العميل مع حالة الخادم الحالية، بدون الحاجة إلى كتابة أي رمز مخصّص.

سنتحدث أكثر عن السلوك خارج الإنترنت في مزيد من المعلومات حول الإمكانات على الإنترنت وبلا إنترنت

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