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

এবার শুরু করা যাক

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

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

ডাটাবেসে ডেটা লিখতে, আপনার DatabaseReference একটি উদাহরণ প্রয়োজন:

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

ডেটা সংরক্ষণ করা হচ্ছে

ফায়ারবেস রিয়েলটাইম ডেটাবেসে ডেটা লেখার জন্য চারটি পদ্ধতি রয়েছে:

পদ্ধতি সাধারণ ব্যবহার
SetValue() একটি সংজ্ঞায়িত পথে ডেটা লিখুন বা প্রতিস্থাপন করুন, যেমন users/<user-id>/<username>
PushChild() ডেটার তালিকায় যোগ করুন। যতবার আপনি Push() কল করেন, ফায়ারবেস একটি অনন্য কী তৈরি করে যা একটি অনন্য শনাক্তকারী হিসাবেও ব্যবহার করা যেতে পারে, যেমন user-scores/<user-id>/<unique-score-id>
UpdateChildren() সমস্ত ডেটা প্রতিস্থাপন না করে একটি সংজ্ঞায়িত পথের জন্য কিছু কী আপডেট করুন।
RunTransaction() সমসাময়িক আপডেট দ্বারা দূষিত হতে পারে এমন জটিল ডেটা আপডেট করুন।

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

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

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

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

এইভাবে SetValue() ব্যবহার করে যেকোন চাইল্ড নোড সহ নির্দিষ্ট স্থানে ডেটা ওভাররাইট করে। যাইহোক, আপনি এখনও সম্পূর্ণ বস্তুটি পুনরায় লেখা ছাড়াই একটি শিশুকে আপডেট করতে পারেন। আপনি যদি ব্যবহারকারীদের তাদের প্রোফাইল আপডেট করার অনুমতি দিতে চান তবে আপনি নিম্নরূপ ব্যবহারকারীর নাম আপডেট করতে পারেন:

dbref.Child("users").Child(userId).Child("username").SetValue(name);

ডেটার তালিকায় যুক্ত করুন

মাল্টি-ইউজার অ্যাপ্লিকেশনের তালিকায় ডেটা যুক্ত করতে PushChild() পদ্ধতি ব্যবহার করুন। 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 রিয়েলটাইম ডেটাবেস সার্ভারে প্রতিশ্রুতিবদ্ধ তা জানতে, সাফল্যের জন্য ভবিষ্যতের ফলাফল দেখুন।

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

ক্রমবর্ধমান কাউন্টারগুলির মতো সমসাময়িক পরিবর্তন দ্বারা দূষিত হতে পারে এমন ডেটা নিয়ে কাজ করার সময়, আপনি একটি লেনদেন অপারেশন ব্যবহার করতে পারেন। আপনি এই অপারেশনটিকে একটি 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;
  });
}

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

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

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

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

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

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

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