Bắt đầu
Trước tiên, hãy xem hướng dẫn về Get Started
nếu bạn chưa
thiết lập ứng dụng và truy cập vào cơ sở dữ liệu.
Nhận một DatabaseReference
Để ghi dữ liệu vào Cơ sở dữ liệu, bạn cần có một thực thể của DatabaseReference
:
// Get the root reference location of the database. firebase::database::DatabaseReference dbref = database->GetReference();
Đang lưu dữ liệu
Có 4 phương thức để ghi dữ liệu vào Firebase Realtime Database:
Phương thức | Các cách dùng phổ biến |
---|---|
SetValue() |
Ghi hoặc thay thế dữ liệu vào một đường dẫn đã xác định, chẳng hạn như
users/<user-id>/<username> . |
PushChild() |
Thêm vào danh sách dữ liệu. Mỗi khi bạn gọi
Push() , Firebase sẽ tạo một khoá duy nhất mà bạn cũng có thể sử dụng
làm giá trị nhận dạng duy nhất, chẳng hạn như
user-scores/<user-id>/<unique-score-id> . |
UpdateChildren() |
Cập nhật một số khoá cho đường dẫn đã xác định mà không thay thế tất cả dữ liệu. |
RunTransaction() |
Cập nhật những dữ liệu phức tạp có thể bị hỏng do các bản cập nhật đồng thời. |
Ghi, cập nhật hoặc xoá dữ liệu tại một tham chiếu
Thao tác ghi cơ bản
Đối với các thao tác ghi cơ bản, bạn có thể sử dụng SetValue()
để lưu dữ liệu vào một
tham chiếu cụ thể, thay thế mọi dữ liệu hiện có tại đường dẫn đó. Bạn có thể dùng
để truyền các loại được JSON chấp nhận thông qua loại Biến thể hỗ trợ:
- Rỗng (thao tác này sẽ xoá dữ liệu)
- Số nguyên (64 bit)
- Số có dấu phẩy động với độ chính xác gấp đôi
- Boolean (logic)
- Chuỗi
- Vectơ của các biến thể
- Sơ đồ ánh xạ các chuỗi đến Biến thể
Việc sử dụng SetValue()
theo cách này sẽ ghi đè dữ liệu tại vị trí được chỉ định,
bao gồm mọi nút con. Tuy nhiên, bạn vẫn có thể cập nhật tài khoản của trẻ mà không cần
viết lại toàn bộ đối tượng. Nếu bạn muốn cho phép người dùng cập nhật hồ sơ của họ
bạn có thể cập nhật tên người dùng như sau:
dbref.Child("users").Child(userId).Child("username").SetValue(name);
Thêm vào danh sách dữ liệu
Sử dụng phương thức PushChild()
để nối dữ liệu vào một danh sách trong các ứng dụng nhiều người dùng.
Phương thức PushChild()
tạo một khoá duy nhất mỗi khi có một khoá mới
con sẽ được thêm vào tham chiếu Firebase được chỉ định. Bằng cách sử dụng
khoá được tạo tự động cho từng phần tử mới trong danh sách, một số khách hàng có thể
thêm thành phần con vào cùng một vị trí cùng lúc mà không bị xung đột khi ghi. Chiến lược phát hành đĩa đơn
khoá duy nhất do PushChild()
tạo là dựa trên dấu thời gian, vì vậy các mục trong danh sách
tự động sắp xếp theo trình tự thời gian.
Bạn có thể sử dụng tham chiếu đến dữ liệu mới được phương thức PushChild()
trả về
để lấy giá trị khoá được tạo tự động của nhà xuất bản con hoặc đặt dữ liệu cho khoá đó.
Việc gọi GetKey()
trên tham chiếu PushChild()
sẽ trả về giá trị của
khoá được tạo tự động.
Cập nhật các trường cụ thể
Để ghi đồng thời vào các phần tử con cụ thể của một nút mà không ghi đè lên các nút khác
nút con, hãy sử dụng phương thức UpdateChildren()
.
Khi gọi UpdateChildren()
, bạn có thể cập nhật các giá trị con ở cấp thấp hơn bằng cách
chỉ định đường dẫn cho khoá. Nếu dữ liệu được lưu trữ ở nhiều vị trí để mở rộng quy mô
tốt hơn, bạn có thể cập nhật tất cả các phiên bản của dữ liệu đó bằng cách sử dụng
ngừng sử dụng dữ liệu. Ví dụ: một
trò chơi có thể có lớp LeaderboardEntry
như sau:
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; } }
Để tạo một LeaderboardEntry
đồng thời cập nhật nó lên điểm số gần đây
nguồn cấp dữ liệu và danh sách điểm số của riêng người dùng, trò chơi sẽ sử dụng mã sau:
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); }
Ví dụ này sử dụng PushChild()
để tạo một mục nhập trong nút chứa
cho tất cả người dùng tại /scores/$key
và truy xuất khoá đồng thời bằng
key()
. Sau đó, khoá này có thể được dùng để tạo mục nhập thứ hai trong tài khoản
điểm số tại /user-scores/$userid/$key
.
Khi sử dụng các đường dẫn này, bạn có thể cập nhật đồng thời nhiều vị trí trong
cây JSON với một lệnh gọi duy nhất đến UpdateChildren()
, chẳng hạn như lệnh gọi này
sẽ tạo mục nhập mới ở cả hai vị trí. Đã thực hiện cập nhật đồng thời
nguyên tử: tất cả cập nhật thành công hoặc tất cả cập nhật đều không thành công.
Xóa dữ liệu
Cách đơn giản nhất để xoá dữ liệu là gọi RemoveValue()
trên một tham chiếu đến
vị trí của dữ liệu đó.
Bạn cũng có thể xoá bằng cách chỉ định null
Variant
làm giá trị cho lần ghi khác
chẳng hạn như SetValue()
hoặc UpdateChildren()
. Bạn có thể dùng
kỹ thuật dùng UpdateChildren()
để xoá nhiều phần tử con trong một API
.
Biết khi nào dữ liệu của bạn được cam kết.
Để biết thời điểm dữ liệu của bạn được cam kết với máy chủ Firebase Realtime Database, hãy kiểm tra kết quả tương lai để thành công.
Lưu dữ liệu dưới dạng giao dịch
Khi làm việc với dữ liệu có thể bị hỏng do đồng thời
sửa đổi, chẳng hạn như bộ đếm tăng dần, bạn có thể sử dụng
hoạt động giao dịch.
Bạn cung cấp cho toán tử này một hàm DoTransaction
. Hàm cập nhật này sẽ mất
trạng thái hiện tại của dữ liệu làm đối số và trả về trạng thái mong muốn mới
mà bạn muốn viết. Nếu một khách hàng khác ghi vào vị trí trước
giá trị mới đã được ghi thành công, hàm cập nhật của bạn sẽ được gọi lại bằng
giá trị hiện tại mới và quá trình ghi được thử lại.
Ví dụ: trong một trò chơi, bạn có thể cho phép người dùng cập nhật bảng xếp hạng bằng 5 điểm số cao nhất:
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; }); }
Việc sử dụng giao dịch sẽ giúp bảng xếp hạng không bị sai lệch nếu có nhiều người dùng ghi lại điểm số cùng lúc hoặc ứng dụng có dữ liệu lỗi thời. Nếu giao dịch bị từ chối, máy chủ trả về giá trị hiện tại cho máy khách, Thao tác này sẽ chạy lại giao dịch với giá trị được cập nhật. Thao tác này lặp lại cho đến khi giao dịch được chấp nhận hoặc bạn đã thử quá nhiều lần.
Ghi dữ liệu khi không có mạng
Nếu máy khách bị mất kết nối mạng, ứng dụng của bạn sẽ tiếp tục hoạt động chính xác.
Mỗi ứng dụng được kết nối với cơ sở dữ liệu Firebase đều duy trì phiên bản nội bộ riêng của mọi dữ liệu đang hoạt động. Khi được ghi, dữ liệu sẽ được ghi vào phiên bản cục bộ này đầu tiên. Sau đó, ứng dụng Firebase sẽ đồng bộ hoá dữ liệu đó với cơ sở dữ liệu từ xa máy chủ của bạn và với các ứng dụng khách khác với "nỗ lực tối đa" cơ sở.
Do đó, tất cả hoạt động ghi vào cơ sở dữ liệu sẽ kích hoạt các sự kiện cục bộ ngay lập tức, trước khi mọi dữ liệu đều được ghi vào máy chủ. Tức là ứng dụng của bạn vẫn hoạt động thích ứng bất kể độ trễ hoặc khả năng kết nối mạng như thế nào.
Sau khi kết nối được thiết lập lại, ứng dụng của bạn sẽ nhận được nhóm các sự kiện để máy khách đồng bộ hóa với trạng thái máy chủ hiện tại mà không phải viết bất kỳ mã tuỳ chỉnh nào.