C++ के लिए, Firebase रीयल टाइम डेटाबेस की मदद से डेटा सेव करना

शुरू करें

अगर आपने अब तक अपना ऐप्लिकेशन और डेटाबेस का ऐक्सेस सेट अप नहीं किया है, तो पहले Get Started गाइड देखें.

DatabaseReference पाना

डेटाबेस में डेटा लिखने के लिए, आपको 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 के साथ काम करने वाले टाइप को वैरिएंट टाइप के ज़रिए पास किया जा सकता है. वैरिएंट टाइप में ये चीज़ें शामिल हैं:

  • Null (इससे डेटा मिट जाता है)
  • पूर्णांक (64-बिट)
  • डबल प्रिसिज़न फ़्लोटिंग पॉइंट नंबर
  • बूलियन
  • स्ट्रिंग
  • वैरिएंट के वेक्टर
  • Maps of strings to Variants

इस तरह से SetValue() का इस्तेमाल करने पर, तय की गई जगह पर मौजूद डेटा को ओवरराइट कर दिया जाता है. इसमें सभी चाइल्ड नोड भी शामिल हैं. हालांकि, पूरे ऑब्जेक्ट को फिर से लिखे बिना भी चाइल्ड को अपडेट किया जा सकता है. अगर आपको उपयोगकर्ताओं को अपनी प्रोफ़ाइल अपडेट करने की अनुमति देनी है, तो उपयोगकर्ता नाम को इस तरह अपडेट किया जा सकता है:

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

डेटा की सूची में जोड़ना

एक से ज़्यादा उपयोगकर्ताओं वाले ऐप्लिकेशन में, किसी सूची में डेटा जोड़ने के लिए PushChild() तरीके का इस्तेमाल करें. PushChild() मेथड, Firebase के किसी रेफ़रंस में नया चाइल्ड जोड़ने पर हर बार एक यूनीक कुंजी जनरेट करता है. सूची में मौजूद हर नए एलिमेंट के लिए, अपने-आप जनरेट होने वाली इन कुंजियों का इस्तेमाल करके, कई क्लाइंट एक ही समय पर एक ही जगह पर चाइल्ड एलिमेंट जोड़ सकते हैं. इससे, डेटा लिखने में कोई समस्या नहीं होती. 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&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() को कॉल करें.

null Variant को किसी अन्य राइट ऑपरेशन, जैसे कि SetValue() या UpdateChildren() की वैल्यू के तौर पर तय करके भी मिटाया जा सकता है. एक ही एपीआई कॉल में कई चाइल्ड ऑब्जेक्ट मिटाने के लिए, UpdateChildren() के साथ इस तकनीक का इस्तेमाल किया जा सकता है.

जानें कि आपका डेटा कब कमिट किया जाता है.

यह जानने के लिए कि आपका डेटा Firebase Realtime Database सर्वर पर कब कमिट किया गया है, फ़्यूचर के नतीजे देखें.

डेटा को लेन-देन के तौर पर सेव करना

जब ऐसे डेटा के साथ काम किया जा रहा हो जो एक साथ किए गए बदलावों की वजह से खराब हो सकता है, जैसे कि बढ़ने वाले काउंटर, तो ट्रांज़ैक्शन ऑपरेशन का इस्तेमाल किया जा सकता है. इस कार्रवाई के लिए, DoTransaction फ़ंक्शन का इस्तेमाल किया जाता है. यह अपडेट फ़ंक्शन, डेटा की मौजूदा स्थिति को आर्ग्युमेंट के तौर पर लेता है और आपकी पसंद के मुताबिक नई स्थिति दिखाता है. अगर कोई दूसरा क्लाइंट आपकी नई वैल्यू को सेव करने से पहले, उस जगह पर कोई वैल्यू सेव करता है, तो आपके अपडेट फ़ंक्शन को नई मौजूदा वैल्यू के साथ फिर से कॉल किया जाता है. साथ ही, वैल्यू को सेव करने की कोशिश फिर से की जाती है.

उदाहरण के लिए, किसी गेम में उपयोगकर्ताओं को पांच सबसे ज़्यादा स्कोर के साथ लीडरबोर्ड अपडेट करने की अनुमति दी जा सकती है:

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 क्लाइंट उस डेटा को रिमोट डेटाबेस सर्वर और अन्य क्लाइंट के साथ "सबसे बेहतर तरीके" से सिंक करता है.

इस वजह से, डेटाबेस में कुछ भी लिखने पर, सर्वर में कोई डेटा लिखे जाने से पहले ही लोकल इवेंट तुरंत ट्रिगर हो जाते हैं. इसका मतलब है कि नेटवर्क की इंतज़ार की अवधि या कनेक्टिविटी की परवाह किए बिना, आपका ऐप्लिकेशन रिस्पॉन्सिव बना रहता है.

कनेक्टिविटी फिर से चालू होने पर, आपके ऐप्लिकेशन को इवेंट का सही सेट मिलता है. इससे क्लाइंट, सर्वर की मौजूदा स्थिति के साथ सिंक हो जाता है. इसके लिए, कोई कस्टम कोड लिखने की ज़रूरत नहीं पड़ती.

अगले चरण