डेटा पढ़ें और लिखें

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.

(वैकल्पिक) Firebase Emulator Suite के साथ प्रोटोटाइप और परीक्षण

इस बारे में बात करने से पहले कि आपका ऐप रीयलटाइम डेटाबेस से कैसे पढ़ता है और लिखता है, आइए ऐसे टूल का एक सेट पेश करें जिनका उपयोग आप रीयलटाइम डेटाबेस कार्यक्षमता के प्रोटोटाइप और परीक्षण के लिए कर सकते हैं: फायरबेस एमुलेटर सूट। यदि आप अलग-अलग डेटा मॉडल आज़मा रहे हैं, अपने सुरक्षा नियमों का अनुकूलन कर रहे हैं, या बैक-एंड के साथ इंटरैक्ट करने का सबसे किफ़ायती तरीका खोजने के लिए काम कर रहे हैं, तो लाइव सेवाओं को लागू किए बिना स्थानीय रूप से काम करने में सक्षम होना एक अच्छा विचार हो सकता है।

एक रीयलटाइम डेटाबेस एमुलेटर एमुलेटर सूट का हिस्सा है, जो आपके ऐप को आपकी एमुलेटेड डेटाबेस सामग्री और कॉन्फ़िगरेशन के साथ-साथ वैकल्पिक रूप से आपके नकली प्रोजेक्ट संसाधनों (फ़ंक्शंस, अन्य डेटाबेस और सुरक्षा नियम) के साथ इंटरैक्ट करने में सक्षम बनाता है।emulator_suite_short

रीयलटाइम डेटाबेस एमुलेटर का उपयोग करने में कुछ ही चरण शामिल हैं:

  1. एमुलेटर से कनेक्ट करने के लिए अपने ऐप के टेस्ट कॉन्फिगर में कोड की एक लाइन जोड़ना।
  2. अपनी स्थानीय परियोजना निर्देशिका की जड़ से, firebase emulators:start
  3. हमेशा की तरह रीयलटाइम डेटाबेस प्लेटफ़ॉर्म SDK का उपयोग करके या रीयलटाइम डेटाबेस REST API का उपयोग करके अपने ऐप के प्रोटोटाइप कोड से कॉल करना।

रीयलटाइम डेटाबेस और क्लाउड फ़ंक्शंस को शामिल करते हुए एक विस्तृत पूर्वाभ्यास उपलब्ध है। आपको एमुलेटर सूट परिचय पर भी एक नज़र डालनी चाहिए।

एक डेटाबेस संदर्भ प्राप्त करें

डेटाबेस से डेटा पढ़ने या लिखने के लिए, आपको DatabaseReference का एक उदाहरण चाहिए:

DatabaseReference ref = FirebaseDatabase.instance.ref();

डेटा लिखें

इस दस्तावेज़ में Firebase डेटा पढ़ने और लिखने की मूल बातें शामिल हैं।

फायरबेस डेटा DatabaseReference रेफरेंस को लिखा जाता है और संदर्भ द्वारा उत्सर्जित घटनाओं की प्रतीक्षा या सुनने के द्वारा पुनर्प्राप्त किया जाता है। डेटा की प्रारंभिक स्थिति के लिए ईवेंट एक बार उत्सर्जित होते हैं और फिर कभी भी डेटा में परिवर्तन होता है।

बेसिक राइट ऑपरेशंस

बुनियादी लेखन कार्यों के लिए, आप किसी निर्दिष्ट संदर्भ में डेटा को सहेजने के लिए set() का उपयोग कर सकते हैं, उस पथ पर किसी भी मौजूदा डेटा को बदल सकते हैं। आप निम्न प्रकारों के लिए एक संदर्भ सेट कर सकते हैं: String , boolean , int , double , Map , List

उदाहरण के लिए, आप एक उपयोगकर्ता को set() के साथ जोड़ सकते हैं:

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

await ref.set({
  "name": "John",
  "age": 18,
  "address": {
    "line1": "100 Mountain View"
  }
});

इस तरह से set() का उपयोग किसी भी बच्चे के नोड्स सहित निर्दिष्ट स्थान पर डेटा को अधिलेखित कर देता है। हालाँकि, आप अभी भी संपूर्ण ऑब्जेक्ट को फिर से लिखे बिना किसी बच्चे को अपडेट कर सकते हैं। यदि आप उपयोगकर्ताओं को अपनी प्रोफ़ाइल अपडेट करने की अनुमति देना चाहते हैं तो आप उपयोगकर्ता नाम को निम्नानुसार अपडेट कर सकते हैं:

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

// Only update the name, leave the age and address!
await ref.update({
  "age": 19,
});

update() विधि नोड्स के लिए एक उप-पथ स्वीकार करती है, जिससे आप डेटाबेस पर एक साथ कई नोड्स को अपडेट कर सकते हैं:

DatabaseReference ref = FirebaseDatabase.instance.ref("users");

await ref.update({
  "123/age": 19,
  "123/address/line1": "1 Mountain View",
});

डेटा पढ़ें

महत्वपूर्ण घटनाओं को सुनकर डेटा पढ़ें

किसी पथ पर डेटा पढ़ने और परिवर्तनों को सुनने के लिए, DatabaseEvent के onValue गुण का उपयोग DatabaseReference s को सुनने के लिए करें।

आप किसी दिए गए पथ पर डेटा पढ़ने के लिए DatabaseEvent का उपयोग कर सकते हैं, क्योंकि यह घटना के समय मौजूद है। यह घटना एक बार चालू हो जाती है जब श्रोता संलग्न होता है और फिर से हर बार डेटा, जिसमें कोई भी बच्चा शामिल है, बदलता है। ईवेंट में एक snapshot प्रॉपर्टी होती है जिसमें चाइल्ड डेटा सहित उस स्थान का सभी डेटा होता है। यदि कोई डेटा नहीं exists , तो स्नैपशॉट की मौजूदा संपत्ति false होगी और इसकी value संपत्ति शून्य होगी।

निम्न उदाहरण डेटाबेस से किसी पोस्ट के विवरण को पुनर्प्राप्त करने वाले एक सामाजिक ब्लॉगिंग एप्लिकेशन को प्रदर्शित करता है:

DatabaseReference starCountRef =
        FirebaseDatabase.instance.ref('posts/$postId/starCount');
starCountRef.onValue.listen((DatabaseEvent event) {
    final data = event.snapshot.value;
    updateStarCount(data);
});

श्रोता को एक DataSnapshot प्राप्त होता है जिसमें घटना के समय डेटाबेस में निर्दिष्ट स्थान पर डेटा होता value

एक बार डेटा पढ़ें

प्राप्त () का उपयोग करके एक बार पढ़ें

एसडीके को डेटाबेस सर्वर के साथ बातचीत को प्रबंधित करने के लिए डिज़ाइन किया गया है, चाहे आपका ऐप ऑनलाइन हो या ऑफलाइन।

आम तौर पर, आपको बैकएंड से डेटा के अपडेट की सूचना प्राप्त करने के लिए डेटा पढ़ने के लिए ऊपर वर्णित मूल्य ईवेंट तकनीकों का उपयोग करना चाहिए। वे तकनीक आपके उपयोग और बिलिंग को कम करती हैं, और आपके उपयोगकर्ताओं को ऑनलाइन और ऑफलाइन होने पर सर्वोत्तम अनुभव देने के लिए अनुकूलित हैं।

यदि आपको केवल एक बार डेटा की आवश्यकता है, तो आप डेटाबेस से डेटा का स्नैपशॉट प्राप्त करने के लिए get() का उपयोग कर सकते हैं। यदि किसी कारण get() सर्वर मान वापस करने में असमर्थ है, तो क्लाइंट स्थानीय भंडारण कैश की जांच करेगा और यदि मान अभी भी नहीं मिला है तो एक त्रुटि लौटाएगा।

निम्न उदाहरण डेटाबेस से एक बार उपयोगकर्ता के सार्वजनिक-सामना करने वाले उपयोगकर्ता नाम को पुनर्प्राप्त करने का प्रदर्शन करता है:

final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
    print(snapshot.value);
} else {
    print('No data available.');
}

get() का अनावश्यक उपयोग बैंडविड्थ के उपयोग को बढ़ा सकता है और प्रदर्शन के नुकसान का कारण बन सकता है, जिसे ऊपर दिखाए गए रीयलटाइम श्रोता का उपयोग करके रोका जा सकता है।

एक बार के साथ डेटा पढ़ें ()

कुछ मामलों में आप चाहते हैं कि सर्वर पर अद्यतन मान की जाँच करने के बजाय स्थानीय कैश से मान तुरंत लौटाया जाए। उन मामलों में आप स्थानीय डिस्क कैश से डेटा तुरंत प्राप्त करने के लिए once() का उपयोग कर सकते हैं।

यह डेटा के लिए उपयोगी है जिसे केवल एक बार लोड करने की आवश्यकता होती है और जिसके बार-बार बदलने या सक्रिय सुनने की आवश्यकता नहीं होती है। उदाहरण के लिए, पिछले उदाहरणों में ब्लॉगिंग ऐप इस पद्धति का उपयोग उपयोगकर्ता के प्रोफ़ाइल को लोड करने के लिए करता है जब वे एक नया पोस्ट लिखना शुरू करते हैं:

final event = await ref.once(DatabaseEventType.value);
final username = event.snapshot.value?.username ?? 'Anonymous';

डेटा अपडेट करना या हटाना

विशिष्ट फ़ील्ड अपडेट करें

अन्य चाइल्ड नोड्स को अधिलेखित किए बिना एक नोड के विशिष्ट बच्चों को एक साथ लिखने के लिए, update() विधि का उपयोग करें।

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

void writeNewPost(String uid, String username, String picture, String title,
        String body) async {
    // A post entry.
    final postData = {
        'author': username,
        'uid': uid,
        'body': body,
        'title': title,
        'starCount': 0,
        'authorPic': picture,
    };

    // Get a key for a new Post.
    final newPostKey =
        FirebaseDatabase.instance.ref().child('posts').push().key;

    // Write the new post's data simultaneously in the posts list and the
    // user's post list.
    final Map<String, Map> updates = {};
    updates['/posts/$newPostKey'] = postData;
    updates['/user-posts/$uid/$newPostKey'] = postData;

    return FirebaseDatabase.instance.ref().update(updates);
}

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

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

एक पूर्ण कॉलबैक जोड़ें

यदि आप जानना चाहते हैं कि आपका डेटा कब प्रतिबद्ध किया गया है, तो आप पूर्ण कॉलबैक पंजीकृत कर सकते हैं। दोनों set() और update() Future s लौटाते हैं, जिसमें आप सफलता और त्रुटि कॉलबैक संलग्न कर सकते हैं जिन्हें तब कहा जाता है जब डेटाबेस के लिए लेखन किया गया हो और जब कॉल असफल हो।

FirebaseDatabase.instance
    .ref('users/$userId/email')
    .set(emailAddress)
    .then((_) {
        // Data saved successfully!
    })
    .catchError((error) {
        // The write failed...
    });

डेटा हटाएं

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

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

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

डेटा के साथ काम करते समय जो समवर्ती संशोधनों से दूषित हो सकता है, जैसे कि वृद्धिशील काउंटर, आप लेन-देन हैंडलर को runTransaction() पास करके लेनदेन का उपयोग कर सकते हैं। एक लेन-देन हैंडलर डेटा की वर्तमान स्थिति को एक तर्क के रूप में लेता है और नई वांछित स्थिति देता है जिसे आप लिखना चाहते हैं। यदि आपका नया मान सफलतापूर्वक लिखे जाने से पहले कोई अन्य क्लाइंट स्थान पर लिखता है, तो आपके अपडेट फ़ंक्शन को नए वर्तमान मान के साथ फिर से कॉल किया जाता है, और लिखने का पुन: प्रयास किया जाता है।

उदाहरण के लिए, उदाहरण के लिए सोशल ब्लॉगिंग ऐप में, आप उपयोगकर्ताओं को पोस्ट को तारांकित और अतारांकित करने की अनुमति दे सकते हैं और यह ट्रैक कर सकते हैं कि किसी पोस्ट को कितने सितारे मिले हैं:

void toggleStar(String uid) async {
  DatabaseReference postRef =
      FirebaseDatabase.instance.ref("posts/foo-bar-123");

  TransactionResult result = await postRef.runTransaction((Object? post) {
    // Ensure a post at the ref exists.
    if (post == null) {
      return Transaction.abort();
    }

    Map<String, dynamic> _post = Map<String, dynamic>.from(post as Map);
    if (_post["stars"] is Map && _post["stars"][uid] != null) {
      _post["starCount"] = (_post["starCount"] ?? 1) - 1;
      _post["stars"][uid] = null;
    } else {
      _post["starCount"] = (_post["starCount"] ?? 0) + 1;
      if (!_post.containsKey("stars")) {
        _post["stars"] = {};
      }
      _post["stars"][uid] = true;
    }

    // Return the new data.
    return Transaction.success(_post);
  });
}

डिफ़ॉल्ट रूप से, हर बार लेन-देन अद्यतन फ़ंक्शन चलने पर ईवेंट उठाए जाते हैं, इसलिए आप फ़ंक्शन को कई बार चलाते हैं, आप मध्यवर्ती स्थिति देख सकते हैं। आप इन मध्यवर्ती राज्यों को दबाने के लिए लागू स्थानीय रूप से applyLocally पर सेट कर सकते हैं और इसके बजाय तब तक प्रतीक्षा करें जब तक कि घटनाओं को उठाए जाने से पहले लेनदेन पूरा न false जाए:

await ref.runTransaction((Object? post) {
  // ...
}, applyLocally: false);

लेन-देन का परिणाम एक TransactionResult है, जिसमें इस तरह की जानकारी होती है कि क्या लेन-देन किया गया था, और नया स्नैपशॉट:

DatabaseReference ref = FirebaseDatabase.instance.ref("posts/123");

TransactionResult result = await ref.runTransaction((Object? post) {
  // ...
});

print('Committed? ${result.committed}'); // true / false
print('Snapshot? ${result.snapshot}'); // DataSnapshot

लेन-देन रद्द करना

यदि आप किसी लेन-देन को सुरक्षित रूप से रद्द करना चाहते हैं, तो Transaction.abort() को AbortTransactionException फेंकने के लिए कॉल करें:

TransactionResult result = await ref.runTransaction((Object? user) {
  if (user !== null) {
    return Transaction.abort();
  }

  // ...
});

print(result.committed); // false

परमाणु सर्वर-साइड वेतन वृद्धि

उपरोक्त उपयोग के मामले में हम डेटाबेस में दो मान लिख रहे हैं: उपयोगकर्ता की आईडी जो पोस्ट को तारांकित/अतारांकित करता है, और बढ़ी हुई स्टार गिनती। यदि हम पहले से ही जानते हैं कि उपयोगकर्ता पोस्ट को तारांकित कर रहा है, तो हम लेनदेन के बजाय परमाणु वृद्धि संचालन का उपयोग कर सकते हैं।

void addStar(uid, key) async {
  Map<String, Object?> updates = {};
  updates["posts/$key/stars/$uid"] = true;
  updates["posts/$key/starCount"] = ServerValue.increment(1);
  updates["user-posts/$key/stars/$uid"] = true;
  updates["user-posts/$key/starCount"] = ServerValue.increment(1);
  return FirebaseDatabase.instance.ref().update(updates);
}

यह कोड लेन-देन संचालन का उपयोग नहीं करता है, इसलिए यदि कोई विरोधाभासी अद्यतन है तो यह स्वचालित रूप से फिर से नहीं चलता है। हालांकि, चूंकि इंक्रीमेंट ऑपरेशन सीधे डेटाबेस सर्वर पर होता है, इसलिए विरोध की कोई संभावना नहीं है।

यदि आप एप्लिकेशन-विशिष्ट विरोधों का पता लगाना और अस्वीकार करना चाहते हैं, जैसे कि कोई उपयोगकर्ता किसी पोस्ट को अभिनीत करता है, जिसे उन्होंने पहले ही तारांकित किया है, तो आपको उस उपयोग के मामले के लिए कस्टम सुरक्षा नियम लिखना चाहिए।

डेटा के साथ ऑफ़लाइन काम करें

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

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

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

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

हम ऑनलाइन और ऑफलाइन क्षमताओं के बारे में अधिक जानें में ऑफ़लाइन व्यवहार के बारे में अधिक बात करेंगे।

अगले कदम