البدء
اطّلِع على دليل Get Started
أولاً إذا لم يسبق لك
إعداد تطبيقك والوصول إلى قاعدة البيانات.
الحصول على DatabaseReference
لكتابة البيانات في قاعدة البيانات، تحتاج إلى مثيل من DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
حفظ البيانات
هناك أربع طرق لكتابة البيانات في Firebase Realtime Database:
الطريقة | طرق الاستخدام الشائعة |
---|---|
SetValue() |
كتابة البيانات أو استبدالها في مسار محدّد، مثل
users/<user-id>/<username> |
PushChild() |
الإضافة إلى قائمة بيانات في كل مرة تستدعي فيها
Push() ، ينشئ Firebase مفتاحًا فريدًا يمكن استخدامه أيضًا
كمعرّف فريد، مثل
user-scores/<user-id>/<unique-score-id> . |
UpdateChildren() |
تعديل بعض المفاتيح لمسار محدّد بدون استبدال كل البيانات |
RunTransaction() |
تعديل البيانات المعقدة التي يمكن أن تتلف بسبب التحديثات المتزامنة |
كتابة بيانات أو تعديلها أو حذفها في مرجع
عمليات الكتابة الأساسية
بالنسبة إلى عمليات الكتابة الأساسية، يمكنك استخدام SetValue()
لحفظ البيانات في مرجع
محدّد، مع استبدال أي بيانات حالية في هذا المسار. يمكنك استخدام هذه
الطريقة لتمرير الأنواع المقبولة من خلال تنسيق JSON من خلال نوع السعر المتغير الذي يتيح ما يلي:
- قيمة فارغة (يؤدي ذلك إلى حذف البيانات)
- الأعداد الصحيحة (64 بت)
- الأعداد العشرية ذات الدقة المزدوجة
- القيم المنطقية
- السلاسل
- متجهات خيارات المنتج
- تعيين سلاسل إلى خيارات المنتج
يؤدي استخدام SetValue()
بهذه الطريقة إلى استبدال البيانات في الموقع المحدّد،
بما في ذلك أيّ عقد فرعية. ومع ذلك، لا يزال بإمكانك تعديل عنصر فرعي بدون
إعادة كتابة العنصر بأكمله. إذا أردت السماح للمستخدمين بتعديل ملفاتهم الشخصية،
يمكنك تعديل اسم المستخدم على النحو التالي:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
إلحاق البيانات بقائمة بيانات
استخدِم الطريقة PushChild()
لإلحاق البيانات بقائمة في تطبيقات متعددة المستخدمين.
تُنشئ الطريقة PushChild()
مفتاحًا فريدًا في كل مرة تتم فيها إضافة
عنصر فرعي جديد إلى مرجع Firebase المحدّد. باستخدام هذه
المفاتيح التي يتم إنشاؤها تلقائيًا لكل عنصر جديد في القائمة، يمكن لعدة عملاء
إضافة عناصر فرعية إلى الموقع الجغرافي نفسه في الوقت نفسه بدون حدوث تعارضات في الكتابة. يستند
المفتاح الفريد الذي تم إنشاؤه بواسطة PushChild()
إلى طابع زمني، لذلك يتم ترتيب عناصر القائمة
تلقائيًا ترتيبًا زمنيًا.
يمكنك استخدام إشارة إلى البيانات الجديدة التي تعرضها طريقة PushChild()
للحصول على قيمة مفتاح الطفل الذي تم إنشاؤه تلقائيًا أو ضبط بيانات للطفل.
يؤدي استدعاء GetKey()
على مرجع PushChild()
إلى عرض قيمة
المفتاح الذي يتم إنشاؤه تلقائيًا.
تعديل حقول معيّنة
للكتابة في الوقت نفسه في عناصر فرعية محدّدة من عقدة بدون استبدال
العناصر الفرعية الأخرى، استخدِم الطريقة UpdateChildren()
.
عند استدعاء UpdateChildren()
، يمكنك تعديل القيم الفرعية ذات المستوى الأدنى من خلال
تحديد مسار للمفتاح. إذا تم تخزين البيانات في مواقع جغرافية متعددة لتحسين معدّل التوسّع، يمكنك تعديل جميع نُسخ هذه البيانات باستخدام نشر البيانات. على سبيل المثال، قد تحتوي
اللعبة على فئة LeaderboardEntry
على النحو التالي:
class LeaderboardEntry { std::string uid; int score = 0; public: LeaderboardEntry() { } LeaderboardEntry(std::string uid, int score) { this->uid = uid; this->score = score; } std::map<std::string, Object> ToMap() { std::map<string, Variant> result = new std::map<string, Variant>(); result["uid"] = Variant(uid); result["score"] = Variant(score); return result; } }
لإنشاء LeaderboardEntry
وتعديله في الوقت نفسه في خلاصة النتيجة
الأخيرة وقائمة نتائج المستخدم، تستخدم اللعبة الرمز البرمجي التالي:
void WriteNewScore(std::string userId, int score) { // Create new entry at /user-scores/$userid/$scoreid and at // /leaderboard/$scoreid simultaneously std::string key = dbref.Child("scores").PushChild().GetKey(); LeaderBoardEntry entry = new LeaderBoardEntry(userId, score); std::map<std::string, Variant> entryValues = entry.ToMap(); std::map<string, Variant> childUpdates = new std::map<string, Variant>(); childUpdates["/scores/" + key] = entryValues; childUpdates["/user-scores/" + userId + "/" + key] = entryValues; dbref.UpdateChildren(childUpdates); }
يستخدم هذا المثال PushChild()
لإنشاء إدخال في العقدة التي تحتوي على
إدخالات لجميع المستخدمين في /scores/$key
واسترداد المفتاح في الوقت نفسه باستخدام
key()
. يمكن بعد ذلك استخدام المفتاح لإنشاء إدخال ثانٍ في ملف /user-scores/$userid/$key
الخاص بالمستخدم.
باستخدام هذه المسارات، يمكنك إجراء تعديلات متزامنة على مواقع جغرافية متعددة في
شجرة JSON من خلال طلب واحد إلى UpdateChildren()
، مثل الطريقة التي ينشئ بها
هذا المثال الإدخال الجديد في كلا الموقعَين الجغرافيَين. إنّ التعديلات المتزامنة التي يتم إجراؤها بهذه الطريقة
تكون شاملة: إما أن تنجح جميع التعديلات أو تُؤدّي جميعها إلى تعذُّر إكمالها.
حذف البيانات
إنّ أبسط طريقة لحذف البيانات هي استدعاء RemoveValue()
باستخدام مرجع إلى
موقع تلك البيانات.
يمكنك أيضًا إجراء عملية حذف من خلال تحديد null
Variant
كقيمة لعملية كتابة
أخرى، مثل SetValue()
أو UpdateChildren()
. يمكنك استخدام هذه المحاولة مع UpdateChildren()
لحذف عناصر فرعية متعددة في طلب واحد لواجهة برمجة التطبيقات.
معرفة وقت التزام بياناتك
لمعرفة وقت التزام بياناتك بخادم Firebase Realtime Database، تحقّق من نتيجة المستقبل للنجاح.
حفظ البيانات كمعاملات
عند العمل مع بيانات يمكن أن تتلف بسبب تعديلات مماثلة، مثل العدّادات المتزايدة، يمكنك استخدام
عملية معاملة.
يمكنك منح هذه العملية دالة DoTransaction
. تأخذ دالة التعديل هذه
الحالة الحالية للبيانات كوسيطة وتُرجع الحالة الجديدة المطلوبة
التي تريد كتابتها. إذا كتب عميل آخر في الموقع قبل كتابة
القيمة الجديدة بنجاح، يتم استدعاء دالة التعديل مرة أخرى باستخدام
القيمة الحالية الجديدة، ويتم إعادة المحاولة.
على سبيل المثال، في لعبة، يمكنك السماح للمستخدمين بتعديل قائمة الصدارة التي تتضمّن أعلى خمس نتائج:
void AddScoreToLeaders(std::string email, long score, DatabaseReference leaderBoardRef) { leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) { if (mutableData.children_count() >= MaxScores) { long minScore = LONG_MAX; MutableData *minVal = null; std::vector<MutableData> children = mutableData.children(); std::vector<MutableData>::iterator it; for (it = children.begin(); it != children.end(); ++it) { if (!it->value().is_map()) continue; long childScore = (long)it->Child("score").value().int64_value(); if (childScore < minScore) { minScore = childScore; minVal = &*it; } } if (minScore > score) { // The new score is lower than the existing 5 scores, abort. return kTransactionResultAbort; } // Remove the lowest score. children.Remove(minVal); } // Add the new high score. std::map<std::string, Variant> newScoreMap = new std::map<std::string, Variant>(); newScoreMap["score"] = score; newScoreMap["email"] = email; children.Add(newScoreMap); mutableData->set_value(children); return kTransactionResultSuccess; }); }
يمنع استخدام المعاملة ظهور بيانات غير صحيحة في قائمة الصدارة إذا سجّل عدة مستخدمين نتائج في الوقت نفسه أو إذا كانت بيانات العميل قديمة. إذا تم رفض المعاملة، يعرض الخادم القيمة الحالية للبرنامج العميل، الذي يُجري المعاملة مرة أخرى بالقيمة المعدَّلة. ويتكرّر ذلك إلى أن يتم قبول المعاملة أو يتم إجراء عدد كبير جدًا من المحاولات.
كتابة البيانات بلا إنترنت
إذا فقد العميل الاتصال بالشبكة، سيواصل تطبيقك العمل بشكل صحيح.
يحتفظ كلّ عميل متصل بقاعدة بيانات Firebase بنسخته الداخلية من أيّ بيانات نشطة. عند كتابة البيانات، يتم كتابتها في هذا الإصدار المحلي أولاً. بعد ذلك، يُزامن برنامج Firebase هذه البيانات مع قاعدة بيانات المشغّلات البعيدة ومع برامج أخرى على أساس "أقصى جهد".
ونتيجةً لذلك، تؤدي جميع عمليات الكتابة إلى قاعدة البيانات إلى بدء الأحداث المحلية على الفور، قبل كتابة أي بيانات على الخادم. وهذا يعني أنّ تطبيقك يظلّ سريع الاستجابة بغض النظر عن وقت استجابة الشبكة أو الاتصال بها.
بعد إعادة الاتصال، يتلقّى تطبيقك المجموعة المناسبة من الأحداث حتى تتم مزامنة العميل مع حالة الخادم الحالية، بدون الحاجة إلى كتابة أي رمز مخصّص.