ذخیره داده ها با پایگاه داده بیدرنگ Firebase برای C++

شروع کنید

اگر هنوز برنامه خود را راه‌اندازی نکرده‌اید و به پایگاه داده دسترسی ندارید، ابتدا به راهنمای 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 یک کلید منحصر به فرد تولید می‌کند که می‌تواند به عنوان یک شناسه منحصر به فرد نیز استفاده شود، مانند user-scores/<user-id>/<unique-score-id> .
UpdateChildren() به‌روزرسانی برخی از کلیدها برای یک مسیر تعریف‌شده بدون جایگزینی تمام داده‌ها.
RunTransaction() داده‌های پیچیده‌ای را که ممکن است در اثر به‌روزرسانی‌های همزمان خراب شوند، به‌روزرسانی کنید.

نوشتن، به‌روزرسانی یا حذف داده‌ها در یک مرجع

عملیات نوشتن پایه

برای عملیات نوشتن اولیه، می‌توانید SetValue() برای ذخیره داده‌ها در یک مرجع مشخص استفاده کنید و هر داده موجود در آن مسیر را جایگزین کنید. می‌توانید از این متد برای ارسال انواع پذیرفته شده توسط JSON از طریق یک نوع Variant که از موارد زیر پشتیبانی می‌کند، استفاده کنید:

  • Null (این داده را حذف می‌کند)
  • اعداد صحیح (۶۴ بیتی)
  • اعداد ممیز شناور با دقت مضاعف
  • بولی‌ها
  • رشته‌ها
  • بردارهای متغیرها
  • نگاشت رشته‌ها به انواع مختلف

استفاده از SetValue() به این روش، داده‌ها را در مکان مشخص شده، از جمله هر گره فرزند، بازنویسی می‌کند. با این حال، شما هنوز می‌توانید یک فرزند را بدون بازنویسی کل شیء به‌روزرسانی کنید. اگر می‌خواهید به کاربران اجازه دهید پروفایل‌های خود را به‌روزرسانی کنند، می‌توانید نام کاربری را به صورت زیر به‌روزرسانی کنید:

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

به لیستی از داده‌ها اضافه کنید

Use the PushChild() method to append data to a list in multiuser applications. The PushChild() method generates a unique key every time a new child is added to the specified Firebase reference. By using these auto-generated keys for each new element in the list, several clients can add children to the same location at the same time without write conflicts. The unique key generated by PushChild() is based on a timestamp, so list items are automatically ordered chronologically.

شما می‌توانید از ارجاع به داده‌های جدید برگردانده شده توسط متد 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&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() بازیابی می‌کند. سپس می‌توان از این کلید برای ایجاد ورودی دوم در نمرات کاربر در /user-scores/$userid/$key استفاده کرد.

با استفاده از این مسیرها، می‌توانید به‌روزر��انی‌های همزمان را در چندین مکان در درخت JSON با یک فراخوانی UpdateChildren() انجام دهید، مانند نحوه ایجاد ورودی جدید در هر دو مکان در این مثال. به‌روزرسانی‌های همزمان انجام شده به این روش، اتمیک هستند: یا همه به‌روزرسانی‌ها موفق می‌شوند یا همه به‌روزرسانی‌ها شکست می‌خورند.

حذف داده‌ها

ساده‌ترین راه برای حذف داده‌ها، فراخوانی تابع RemoveValue() روی ارجاعی به محل آن داده‌ها است.

همچنین می‌توانید با مشخص کردن یک Variant null به عنوان مقدار برای عملیات نوشتن دیگری مانند SetValue() یا UpdateChildren() آن را حذف کنید. می‌توانید از این تکنیک به همراه UpdateChildren() برای حذف چندین فرزند در یک فراخوانی API واحد استفاده کنید.

بدانید چه زمانی داده‌هایتان ثبت می‌شوند.

برای اطلاع از زمان ثبت داده‌هایتان در سرور Firebase Realtime Database ، نتیجه‌ی Future را برای موفقیت بررسی کنید.

ذخیره داده‌ها به عنوان تراکنش

When working with data that could be corrupted by concurrent modifications, such as incremental counters, you can use a transaction operation . You give this operation a DoTransaction function. This update function takes the current state of the data as an argument and returns the new desired state you would like to write. If another client writes to the location before your new value is successfully written, your update function is called again with the new current value, and the write is retried.

برای مثال، در یک بازی می‌توانید به کاربران اجازه دهید جدول امتیازات را با پنج امتیاز برتر به‌روزرسانی کنند:

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;
  });
}

استفاده از تراکنش از نادرست ��دن جدول امتیازات در صورت ثبت همزمان امتیازات توسط چندین کاربر یا داده‌های قدیمی توسط کلاینت جلوگیری می‌کند. اگر تراکنش رد شود، سرور مقدار فعلی را به کلاینت برمی‌گرداند که دوباره تراکنش را با مقدار به‌روزرسانی‌شده اجرا می‌کند. این کار تا زمانی که تراکنش پذیرفته شود یا تلاش‌های زیادی انجام شود، تکرار می‌شود.

نوشتن داده‌ها به صورت آفلاین

اگر یک کلاینت اتصال شبکه خود را از دست بدهد، برنامه شما به درستی به کار خود ادامه خواهد داد.

هر کلاینت متصل به پایگاه داده Firebase، نسخه داخلی خود را از هر داده فعالی نگهداری می‌کند. وقتی داده‌ها نوشته می‌شوند، ابتدا در این نسخه محلی نوشته می‌شوند. سپس کلاینت Firebase آن داده‌ها را با سرورهای پایگاه داده راه دور و با سایر کلاینت‌ها بر اساس "بهترین تلاش" همگام‌سازی می‌کند.

در نتیجه، تمام نوشته‌ها در پایگاه داده، بلافاصله قبل از اینکه داده‌ای در سرور نوشته شود، رویدادهای محلی را فعال می‌کنند. این بدان معناست که برنامه شما صرف نظر از تأخیر شبکه یا اتصال، پاسخگو باقی می‌ماند.

پس از برقراری مجدد اتصال، برنامه شما مجموعه مناسبی از رویدادها را دریافت می‌کند تا کلاینت بدون نیاز به نوشتن هیچ کد سفارشی، با وضعیت فعلی سرور همگام‌سازی شود.

مراحل بعدی