C++ के लिए फायरबेस रीयलटाइम डेटाबेस के साथ डेटा सहेजना

शुरू हो जाओ

यदि आपने अभी तक अपना ऐप सेट नहीं किया है और डेटाबेस तक पहुंच नहीं बनाई है, तो पहले 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);
}

यह उदाहरण /scores/$key पर सभी उपयोगकर्ताओं के लिए प्रविष्टियों वाले नोड में एक प्रविष्टि बनाने के लिए PushChild() का उपयोग करता है और साथ ही key() के साथ कुंजी पुनर्प्राप्त करता है। कुंजी का उपयोग /user-scores/$userid/$key पर उपयोगकर्ता के स्कोर में दूसरी प्रविष्टि बनाने के लिए किया जा सकता है।

इन पथों का उपयोग करके, आप UpdateChildren() पर एक ही कॉल के साथ JSON ट्री में कई स्थानों पर एक साथ अपडेट कर सकते हैं, जैसे कि यह उदाहरण दोनों स्थानों में नई प्रविष्टि कैसे बनाता है। इस तरह से किए गए एक साथ किए गए अपडेट परमाणु होते हैं: या तो सभी अपडेट सफल होते हैं या सभी अपडेट विफल हो जाते हैं।

डेटा हटाएँ

डेटा को हटाने का सबसे सरल तरीका उस डेटा के स्थान के संदर्भ में RemoveValue() कॉल करना है।

आप SetValue() या UpdateChildren() जैसे किसी अन्य लेखन ऑपरेशन के लिए मान के रूप में एक null Variant निर्दिष्ट करके भी हटा सकते हैं। आप एक ही एपीआई कॉल में एकाधिक बच्चों को हटाने के लिए इस तकनीक का उपयोग UpdateChildren() के साथ कर सकते हैं।

जानें कि आपका डेटा कब प्रतिबद्ध है।

यह जानने के लिए कि आपका डेटा फायरबेस रीयलटाइम डेटाबेस सर्वर के लिए कब प्रतिबद्ध है, सफलता के लिए भविष्य के परिणाम की जांच करें।

लेनदेन के रूप में डेटा सहेजें

डेटा के साथ काम करते समय जो समवर्ती संशोधनों, जैसे वृद्धिशील काउंटरों द्वारा दूषित हो सकता है, आप लेनदेन ऑपरेशन का उपयोग कर सकते हैं। आप इस ऑपरेशन को 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;
  });
}

यदि कई उपयोगकर्ता एक ही समय में स्कोर रिकॉर्ड करते हैं या क्लाइंट के पास पुराना डेटा है तो लेनदेन का उपयोग करने से लीडरबोर्ड गलत होने से बच जाता है। यदि लेनदेन अस्वीकार कर दिया जाता है, तो सर्वर क्लाइंट को वर्तमान मूल्य लौटाता है, जो अद्यतन मूल्य के साथ लेनदेन को फिर से चलाता है। यह तब तक दोहराया जाता है जब तक कि लेनदेन स्वीकार नहीं हो जाता या बहुत अधिक प्रयास नहीं किए जाते।

डेटा ऑफ़लाइन लिखें

यदि कोई क्लाइंट अपना नेटवर्क कनेक्शन खो देता है, तो आपका ऐप सही ढंग से काम करता रहेगा।

फायरबेस डेटाबेस से जुड़ा प्रत्येक क्लाइंट किसी भी सक्रिय डेटा का अपना आंतरिक संस्करण रखता है। जब डेटा लिखा जाता है, तो उसे पहले इस स्थानीय संस्करण में लिखा जाता है। फ़ायरबेस क्लाइंट तब उस डेटा को दूरस्थ डेटाबेस सर्वर और अन्य क्लाइंट के साथ "सर्वोत्तम प्रयास" के आधार पर सिंक्रनाइज़ करता है।

परिणामस्वरूप, सर्वर पर कोई भी डेटा लिखे जाने से पहले, डेटाबेस पर लिखी जाने वाली सभी चीज़ें तुरंत स्थानीय घटनाओं को ट्रिगर करती हैं। इसका मतलब है कि आपका ऐप नेटवर्क विलंबता या कनेक्टिविटी की परवाह किए बिना प्रतिक्रियाशील बना रहता है।

एक बार कनेक्टिविटी पुनः स्थापित हो जाने पर, आपके ऐप को ईवेंट का उचित सेट प्राप्त होता है ताकि क्लाइंट बिना कोई कस्टम कोड लिखे वर्तमान सर्वर स्थिति के साथ समन्वयित हो सके।

अगले कदम