C++ এর জন্য Firebase রিয়েলটাইম ডেটাবেস দিয়ে ডেটা সংরক্ষণ করা হচ্ছে

শুরু করুন

আপনি যদি এখনও আপনার অ্যাপ এবং ডেটাবেসে অ্যাক্সেস সেট আপ না করে থাকেন, তাহলে প্রথমে Get Started গাইডটি দেখুন।

একটি ডেটাবেস রেফারেন্স পান

ডেটাবেসে ডেটা লিখতে হলে, আপনার 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 একটি অনন্য কী (key) তৈরি করে যা একটি অনন্য শনাক্তকারী (unique identifier) ​​হিসেবেও ব্যবহার করা যেতে পারে, যেমন user-scores/<user-id>/<unique-score-id>
UpdateChildren() সমস্ত ডেটা প্রতিস্থাপন না করে একটি নির্দিষ্ট পাথের কিছু কী আপডেট করুন।
RunTransaction() একই সাথে একাধিক আপডেটের কারণে ক্ষতিগ্রস্ত হতে পারে এমন জটিল ডেটা আপডেট করুন।

একটি রেফারেন্সে ডেটা লিখুন, আপডেট করুন বা মুছুন।

মৌলিক লেখার ক্রিয়াকলাপ

সাধারণ রাইট অপারেশনের জন্য, আপনি একটি নির্দিষ্ট রেফারেন্সে ডেটা সেভ করতে SetValue() ব্যবহার করতে পারেন, যা সেই পাথে থাকা যেকোনো বিদ্যমান ডেটাকে প্রতিস্থাপন করে। আপনি এই মেথডটি ব্যবহার করে JSON দ্বারা গৃহীত টাইপগুলোকে একটি Variant টাইপের মাধ্যমে পাস করতে পারেন, যা নিম্নলিখিত বিষয়গুলো সাপোর্ট করে:

  • নাল (এটি ডেটা মুছে দেয়)
  • পূর্ণসংখ্যা (৬৪-বিট)
  • ডাবল প্রিসিশন ফ্লোটিং পয়েন্ট সংখ্যা
  • বুলিয়ান
  • স্ট্রিং
  • বিভিন্ন ভেক্টর
  • স্ট্রিং থেকে ভ্যারিয়েন্টের ম্যাপ

এইভাবে 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&ltstd::string, Object&gt ToMap() {
    std::map&ltstring, Variant&gt result = new std::map&ltstring, Variant&gt();
    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&ltstd::string, Variant&gt entryValues = entry.ToMap();

  std::map&ltstring, Variant&gt childUpdates = new std::map&ltstring, Variant&gt();
  childUpdates["/scores/" + key] = entryValues;
  childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

  dbref.UpdateChildren(childUpdates);
}

এই উদাহরণে PushChild() ব্যবহার করে /scores/$key তে সমস্ত ব্যবহারকারীর এন্ট্রি ধারণকারী নোডে একটি এন্ট্রি তৈরি করা হয় এবং একই সাথে key() দিয়ে key-টি পুনরুদ্ধার করা হয়। এরপর সেই key-টি ব্যবহার করে /user-scores/$userid/$key তে ব্যবহারকারীর স্কোরে একটি দ্বিতীয় এন্ট্রি তৈরি করা যেতে পারে।

এই পাথগুলো ব্যবহার করে, আপনি UpdateChildren() ফাংশনের একটিমাত্র কলের মাধ্যমে JSON ট্রি-এর একাধিক স্থানে একযোগে আপডেট করতে পারেন, যেমনটি এই উদাহরণে উভয় স্থানেই নতুন এন্ট্রি তৈরি করা হয়েছে। এইভাবে করা একযোগে আপডেটগুলো অ্যাটমিক হয়: হয় সব আপডেট সফল হয় অথবা সব আপডেট ব্যর্থ হয়।

ডেটা মুছে ফেলুন

ডেটা মুছে ফেলার সবচেয়ে সহজ উপায় হলো সেই ডেটার অবস্থানের রেফারেন্সের উপর RemoveValue() কল করা।

আপনি SetValue() বা UpdateChildren() এর মতো অন্য কোনো রাইট অপারেশনের ভ্যালু হিসেবে একটি null Variant উল্লেখ করেও ডিলিট করতে পারেন। UpdateChildren() এর সাথে এই কৌশলটি ব্যবহার করে আপনি একটিমাত্র এপিআই কলে একাধিক চাইল্ড ডিলিট করতে পারেন।

আপনার ডেটা কখন সংরক্ষিত হচ্ছে তা জানুন।

আপনার ডেটা কখন Firebase Realtime Database সার্ভারে জমা হচ্ছে তা জানতে, সফলতার জন্য 'Future' ফলাফলটি পরীক্ষা করুন।

লেনদেন হিসেবে ডেটা সংরক্ষণ করুন

যখন এমন ডেটা নিয়ে কাজ করা হয় যা একই সাথে একাধিক পরিবর্তনের ফলে নষ্ট হয়ে যেতে পারে, যেমন ইনক্রিমেন্টাল কাউন্টার, তখন আপনি একটি ট্রানজ্যাকশন অপারেশন ব্যবহার করতে পারেন। এই অপারেশনের জন্য আপনাকে একটি DoTransaction ফাংশন দিতে হয়। এই আপডেট ফাংশনটি আর্গুমেন্ট হিসেবে ডেটার বর্তমান অবস্থা গ্রহণ করে এবং আপনি যে নতুন কাঙ্ক্ষিত অবস্থাটি লিখতে চান, তা রিটার্ন করে। যদি আপনার নতুন মান সফলভাবে লেখার আগেই অন্য কোনো ক্লায়েন্ট সেই লোকেশনে লেখে, তাহলে আপনার আপডেট ফাংশনটি নতুন বর্তমান মান দিয়ে আবার কল করা হয় এবং লেখার চেষ্টাটি পুনরায় করা হয়।

উদাহরণস্বরূপ, একটি গেমে আপনি ব্যবহারকারীদের সর্বোচ্চ পাঁচটি স্কোর দিয়ে একটি লিডারবোর্ড আপডেট করার সুযোগ দিতে পারেন:

void AddScoreToLeaders(std::string email,
                       long score,
                       DatabaseReference leaderBoardRef) {
  leaderBoardRef.RunTransaction([](firebase::database::MutableData* mutableData) {
    if (mutableData.children_count() &gt= MaxScores) {
      long minScore = LONG_MAX;
      MutableData *minVal = null;
      std::vector&ltMutableData&gt children = mutableData.children();
      std::vector&ltMutableData&gt::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 &lt minScore) {
          minScore = childScore;
          minVal = &amp*it;
        }
      }
      if (minScore &gt 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&ltstd::string, Variant&gt newScoreMap =
      new std::map&ltstd::string, Variant&gt();
    newScoreMap["score"] = score;
    newScoreMap["email"] = email;
    children.Add(newScoreMap);
    mutableData->set_value(children);
    return kTransactionResultSuccess;
  });
}

ট্রানজ্যাকশন ব্যবহার করলে লিডারবোর্ড ভুল হওয়া থেকে রক্ষা পায়, যদি একাধিক ব্যবহারকারী একই সময়ে স্কোর রেকর্ড করে অথবা ক্লায়েন্টের কাছে পুরোনো ডেটা থাকে। যদি ট্রানজ্যাকশনটি প্রত্যাখ্যাত হয়, সার্ভার বর্তমান মানটি ক্লায়েন্টকে ফেরত পাঠায়, যা আপডেট করা মান দিয়ে ট্রানজ্যাকশনটি আবার চালায়। এই প্রক্রিয়াটি ততক্ষণ চলতে থাকে যতক্ষণ না ট্রানজ্যাকশনটি গৃহীত হয় অথবা অনেক বেশিবার চেষ্টা করা হয়ে যায়।

অফলাইনে ডেটা লিখুন

যদি কোনো ক্লায়েন্ট তার নেটওয়ার্ক সংযোগ হারায়, আপনার অ্যাপটি সঠিকভাবে কাজ করতে থাকবে।

ফায়ারবেস ডেটাবেসের সাথে সংযুক্ত প্রতিটি ক্লায়েন্ট তার সক্রিয় ডেটার নিজস্ব একটি অভ্যন্তরীণ সংস্করণ বজায় রাখে। যখন ডেটা লেখা হয়, তখন তা প্রথমে এই স্থানীয় সংস্করণে লেখা হয়। এরপর ফায়ারবেস ক্লায়েন্ট সেই ডেটা দূরবর্তী ডেটাবেস সার্ভার এবং অন্যান্য ক্লায়েন্টদের সাথে সর্বাত্মক প্রচেষ্টার ভিত্তিতে সিঙ্ক্রোনাইজ করে।

এর ফলে, সার্ভারে কোনো ডেটা লেখার আগেই, ডেটাবেসে করা সমস্ত রাইট অপারেশন তাৎক্ষণিকভাবে লোকাল ইভেন্ট ট্রিগার করে। এর মানে হলো, নেটওয়ার্ক ল্যাটেন্সি বা কানেক্টিভিটি নির্বিশেষে আপনার অ্যাপটি রেসপন্সিভ থাকে।

সংযোগ পুনঃপ্রতিষ্ঠিত হলে, আপনার অ্যাপটি প্রয়োজনীয় ইভেন্টগুলো পেয়ে যায়, যার ফলে কোনো কাস্টম কোড না লিখেই ক্লায়েন্ট বর্তমান সার্ভার অবস্থার সাথে সিঙ্ক হয়ে যায়।

পরবর্তী পদক্ষেপ