Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

使用適用於 C++ 的 Firebase 實時數據庫保存數據

開始

請參閱Get Started第一導向,如果您還沒有設置您的應用程序和訪問數據庫。

獲取數據庫參考

為了將數據寫入到數據庫中,你需要的實例DatabaseReference

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

保存數據

將數據寫入 Firebase 實時數據庫有四種方法:

方法常見用途
SetValue()寫或替換數據來定義的路徑,諸如users/<user-id>/<username>
PushChild()添加到數據列表。每一次調用Push()火力地堡生成一個唯一密鑰也可以被用作唯一的標識符,例如user-scores/<user-id>/<unique-score-id>
UpdateChildren()在不替換所有數據的情況下更新定義路徑的一些鍵。
RunTransaction()更新可能被並發更新破壞的複雜數據。

在引用處寫入、更新或刪除數據

基本寫操作

對於基本的寫操作,您可以使用SetValue()將數據保存到指定的參考,在該路徑替換現有數據。您可以使用此方法通過支持的 Variant 類型傳遞 JSON 接受的類型:

  • 空(這將刪除數據)
  • 整數(64 位)
  • 雙精度浮點數
  • 布爾值
  • 字符串
  • 變體的向量
  • 字符串到變體的映射

使用SetValue()以這種方式將覆蓋在指定的位置數據,包括所有的子節點。但是,您仍然可以在不重寫整個對象的情況下更新子對象。如果您想允許用戶更新他們的個人資料,您可以按如下方式更新用戶名:

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

附加到數據列表

使用PushChild()方法,將數據追加到多用戶應用程序的列表。所述PushChild()方法生成的唯一密鑰每一個新的子被添加到指定的火力地堡基準時間。通過為列表中的每個新元素使用這些自動生成的鍵,多個客戶端可以同時將子項添加到同一位置而不會發生寫入衝突。通過生成的單獨密鑰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()在一個單一的API調用來刪除多個孩子。

知道您的數據何時提交。

要知道,當你的數據被提交到火力地堡實時數據庫服務器,檢查未來成功的結果。

將數據保存為交易

當有可能由並發修改,如增量計數器被損壞的數據時,您可以使用一個交易操作。你把這個操作的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 客戶端然後在“盡力而為”的基礎上將該數據與遠程數據庫服務器和其他客戶端同步。

因此,在將任何數據寫入服務器之前,對數據庫的所有寫入都會立即觸發本地事件。這意味著無論網絡延遲或連接如何,您的應用程序都會保持響應。

重新建立連接後,您的應用程序會收到一組適當的事件,以便客戶端與當前服務器狀態同步,而無需編寫任何自定義代碼。

下一步