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

शुरू करें

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

DatabaseReference पाएं

डेटाबेस में डेटा लिखने के लिए, आपको DatabaseReference का एक इंस्टेंस चाहिए:

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

डेटा सहेजा जा रहा है

Firebase रीयल टाइम डेटाबेस में डेटा लिखने के चार तरीके हैं:

तरीका सामान्य इस्तेमाल
SetValue() बताए गए पाथ में डेटा लिखें या बदलें, जैसे कि users/<user-id>/<username>.
PushChild() डेटा की सूची में जोड़ें. हर बार Push() को कॉल करने पर, Firebase एक खास कुंजी जनरेट करता है. इसका इस्तेमाल यूनीक आइडेंटिफ़ायर के तौर पर भी किया जा सकता है, जैसे कि user-scores/<user-id>/<unique-score-id>.
UpdateChildren() पूरा डेटा बदले बिना, बताए गए पाथ के लिए कुछ कुंजियों को अपडेट करें.
RunTransaction() वह कॉम्प्लेक्स डेटा अपडेट करें जिसमें एक साथ कई अपडेट होने की वजह से गड़बड़ी हो सकती है.

किसी रेफ़रंस के लिए डेटा लिखना, उसे अपडेट करना या मिटाना

लिखने से जुड़ी बुनियादी कार्रवाइयां

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

  • शून्य (इससे डेटा मिट जाता है)
  • पूर्णांक (64-बिट)
  • डबल सटीक फ़्लोटिंग पॉइंट नंबर
  • बूलियन
  • स्ट्रिंग्स
  • वैरिएंट के वेक्टर
  • स्ट्रिंग के अलग-अलग वैरिएंट के लिए मैप

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

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

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

एक से ज़्यादा उपयोगकर्ताओं वाले ऐप्लिकेशन की किसी सूची में डेटा जोड़ने के लिए, PushChild() तरीके का इस्तेमाल करें. जब भी तय Firebase संदर्भ में किसी नए बच्चे को जोड़ा जाता है, तब 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 के सभी उपयोगकर्ताओं के लिए एंट्री वाले नोड में एंट्री बनाने और key() की मदद से कुंजी वापस पाने के लिए, PushChild() का इस्तेमाल किया गया है. इसके बाद, /user-scores/$userid/$key पर उपयोगकर्ता के स्कोर में दूसरी एंट्री बनाने के लिए, इस कुंजी का इस्तेमाल किया जा सकता है.

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

डेटा मिटाना

डेटा मिटाने का सबसे आसान तरीका यह है कि उस डेटा की जगह के रेफ़रंस पर RemoveValue() को कॉल किया जाए.

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

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

यह जानने के लिए कि आपका डेटा, Firebase रीयल टाइम डेटाबेस सर्वर के साथ कब शेयर होता है, आगे के नतीजे देखें.

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

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

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

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

अगले चरण