শুরু করুন
আপনি এখনও অ্যাপ সেট-আপ না করে থাকলে এবং ডেটাবেস অ্যাক্সেস না করে থাকলে, প্রথমে 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-এর মাধ্যমে গ্রহণ করা ধরনগুলি পাস করার জন্য আপনি এই
পদ্ধতি ব্যবহার করতে পারেন, যা এগুলি সমর্থন করে:
- নাল (এটি ডেটা মুছে দেয়)
- পূর্ণসংখ্যা (৬৪-বিট)
- ডবল প্রিসিশন ফ্লোটিং পয়েন্ট সংখ্যা
- বুলিয়ান
- স্ট্রিং
- ভেরিয়েন্টের ভেক্টর
- ভেরিয়েন্টের সাথে স্ট্রিংয়ের ম্যাপ
এইভাবে SetValue() ব্যবহার করলে, নির্দিষ্ট লোকেশনে থাকা ডেটা ওভাররাইট হয়ে যায়,
এর মধ্যে চাইল্ড নোডও পড়ে। তবে, আপনি এখনও পুরো অবজেক্ট
না লিখেও কোনও বাচ্চাকে আপডেট করতে পারবেন। আপনি যদি ব্যবহারকারীদের তাদের প্রোফাইল আপডেট করার অনুমতি দিতে চান
তাহলে আপনি নিম্নলিখিত উপায়ে ইউজারনেম আপডেট করতে পারেন:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
ডেটার তালিকায় যোগ করা
মাল্টিইউজার অ্যাপ্লিকেশনে কোনও তালিকায় ডেটা যোগ করতে PushChild() পদ্ধতি ব্যবহার করুন।
নির্দিষ্ট Firebase রেফারেন্সে নতুন চাইল্ড যোগ করা হলে, PushChild() পদ্ধতিটি
প্রতিবার একটি অনন্য কী তৈরি করে। তালিকায় প্রতিটি নতুন এলিমেন্টের জন্য এইসব
অটোমেটিক তৈরি কী ব্যবহার করে, একাধিক ক্লায়েন্ট
রাইট কনফ্লিক্ট ছাড়াই একই লোকেশনে একই সময়ে চাইল্ড যোগ করতে পারে। PushChild()-এর তৈরি করা অনন্য কী
টাইমস্ট্যাম্পের উপর ভিত্তি করে তৈরি হয়, তাই তালিকার আইটেমগুলি
কালানুক্রমিকভাবে অটোমেটিক সাজানো হয়।
PushChild() মেথড
থেকে পাওয়া নতুন ডেটার রেফারেন্স ব্যবহার করে আপনি সন্তানের অটোমেটিক তৈরি হওয়া কী-এর ভ্যালু পেতে পারেন অথবা সন্তানের জন্য ডেটা সেট করতে পারেন।
PushChild() রেফারেন্সে GetKey()-কে কল করলে অটোমেটিক তৈরি হওয়া কী-এর
ভ্যালু রিটার্ন করে।
নির্দিষ্ট ফিল্ড আপডেট করা
অন্য চাইল্ড নোড ওভাররাইট না করে, কোনও নোডের নির্দিষ্ট চাইল্ড নোডে একই সাথে লিখতে,
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-এ ব্যবহারকারীর
স্কোরে দ্বিতীয় এন্ট্রি তৈরি করতে কী ব্যবহার করা যেতে পারে।
এইসব পাথ ব্যবহার করে, আপনি UpdateChildren()-এ একটি কল করে JSON ট্রি-তে একাধিক লোকেশন
একসাথে আপডেট করতে পারবেন, যেমন এই
উদাহরণে দেখানো হয়েছে যে কীভাবে দুটি লোকেশনেই নতুন এন্ট্রি তৈরি করা হয়েছে। একই সাথে করা আপডেটগুলি এই
ভাবে অ্যাটমিক হয়: হয় সব আপডেট সফল হয়, নয় সব আপডেট ব্যর্থ হয়।
ডেটা মুছে দেওয়া
ডেটা মুছে ফেলার সবচেয়ে সহজ উপায় হল, সেই ডেটার লোকেশন
রেফারেন্সে RemoveValue() কল করা।
এছাড়াও, আপনি SetValue() বা UpdateChildren()-এর মতো অন্য কোনও লেখার
অপারেশনের জন্য null Variant মান নির্দিষ্ট করে মুছে দিতে পারেন। আপনি এই
টেকনিক UpdateChildren()-এর সাথে ব্যবহার করে একটি API
কলের মাধ্যমে একাধিক বাচ্চা মুছে দিতে পারবেন।
আপনার ডেটা কখন কমিট করা হয় তা জানুন।
আপনার ডেটা কখন 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 ক্লায়েন্ট তারপরে সেই ডেটা রিমোট ডেটাবেস সার্ভার ও অন্যান্য ক্লায়েন্টের সাথে "সর্বোত্তম প্রচেষ্টা" ভিত্তিতে সিঙ্ক্রোনাইজ করে।
এর ফলে, ডেটাবেসে লেখা সব ডেটা, সার্ভারে কোনও ডেটা লেখার আগে অবিলম্বে লোকাল ইভেন্ট ট্রিগার করে। এর অর্থ হল, নেটওয়ার্ক লেটেন্সি বা কানেক্টিভিটি যাই হোক না কেন, আপনার অ্যাপ প্রতিক্রিয়াশীল থাকে।
কানেক্টিভিটি আবার চালু হয়ে গেলে, আপনার অ্যাপ ইভেন্টের উপযুক্ত সেট পায় যাতে ক্লায়েন্ট বর্তমান সার্ভার স্টেটের সাথে সিঙ্ক করতে পারে, এর জন্য কোনও কাস্টম কোড লিখতে হয় না।