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

(वैकल्पिक) फायरबेस लोकल एमुलेटर सूट के साथ प्रोटोटाइप और परीक्षण

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

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

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

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

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

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

डेटाबेस से डेटा पढ़ने या लिखने के लिए, आपको firebase.database.Reference की एक आवृत्ति की आवश्यकता है:

Web modular API

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web namespaced API

var database = firebase.database();

डेटा लिखें

यह दस्तावेज़ डेटा को पुनर्प्राप्त करने और फायरबेस डेटा को ऑर्डर और फ़िल्टर करने के तरीके की मूल बातें शामिल करता है।

firebase.database.Reference के लिए एक अतुल्यकालिक श्रोता संलग्न करके Firebase डेटा पुनर्प्राप्त किया जाता है। डेटा की प्रारंभिक स्थिति के लिए श्रोता को एक बार ट्रिगर किया जाता है और फिर कभी भी डेटा में परिवर्तन होता है।

मूल लेखन कार्य

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

Web modular API

import { getDatabase, ref, set } from "firebase/database";

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web namespaced API

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

set() का उपयोग किसी भी बच्चे के नोड्स सहित निर्दिष्ट स्थान पर डेटा को अधिलेखित कर देता है।

डेटा पढ़ें

महत्वपूर्ण घटनाओं के लिए सुनो

किसी पथ पर डेटा पढ़ने और परिवर्तनों को सुनने के लिए, घटनाओं को देखने के लिए onValue() का उपयोग करें। आप इस घटना का उपयोग किसी दिए गए पथ पर सामग्री के स्थिर स्नैपशॉट को पढ़ने के लिए कर सकते हैं, क्योंकि वे घटना के समय मौजूद थे। यह विधि एक बार चालू हो जाती है जब श्रोता जुड़ा होता है और फिर से हर बार डेटा, बच्चों सहित, बदल जाता है। ईवेंट कॉलबैक एक स्नैपशॉट पारित किया जाता है जिसमें चाइल्ड डेटा सहित उस स्थान पर सभी डेटा होते हैं। यदि कोई डेटा नहीं है, तो जब आप exists() कॉल करते हैं और जब आप null val() कॉल करते हैं तो स्नैपशॉट false हो जाएगा।

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

Web modular API

import { getDatabase, ref, onValue} from "firebase/database";

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web namespaced API

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

श्रोता को एक snapshot प्राप्त होता है जिसमें घटना के समय डेटाबेस में निर्दिष्ट स्थान पर डेटा होता है। आप snapshot में डेटा को val() विधि से पुनः प्राप्त कर सकते हैं।

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

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

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

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

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

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

Web modular API

import { getDatabase, ref, child, get } from "firebase/database";

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web namespaced API

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

एक बार पर्यवेक्षक के साथ डेटा पढ़ें

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

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

Web modular API

import { getDatabase, ref, onValue } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web namespaced API

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

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

विशिष्ट क्षेत्रों को अद्यतन करें

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

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

उदाहरण के लिए, एक सोशल ब्लॉगिंग ऐप एक पोस्ट बना सकता है और साथ ही इसे इस तरह के कोड का उपयोग करके हाल की गतिविधि फ़ीड और पोस्ट करने वाले उपयोगकर्ता की गतिविधि फ़ीड में अपडेट कर सकता है:

Web modular API

import { getDatabase, ref, child, push, update } from "firebase/database";

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web namespaced API

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

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

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

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

यदि आप जानना चाहते हैं कि आपका डेटा कब प्रतिबद्ध किया गया है, तो आप एक पूर्णता कॉलबैक जोड़ सकते हैं। दोनों set() और update() एक वैकल्पिक पूर्णता कॉलबैक लेते हैं, जिसे डेटाबेस में लिखने के लिए प्रतिबद्ध होने पर कहा जाता है। यदि कॉल विफल हो गई थी, तो कॉलबैक को एक त्रुटि ऑब्जेक्ट पारित किया जाता है जो इंगित करता है कि विफलता क्यों हुई।

Web modular API

import { getDatabase, ref, set } from "firebase/database";

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web namespaced API

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

डेटा हटाएं

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

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

एक Promise प्राप्त करें

यह जानने के लिए कि आपका डेटा कब Firebase रीयलटाइम डेटाबेस सर्वर के लिए प्रतिबद्ध है, आप Promise का उपयोग कर सकते हैं। दोनों set() और update() एक Promise वापस कर सकते हैं जिसका उपयोग आप यह जानने के लिए कर सकते हैं कि डेटाबेस में लेखन कब किया जाता है।

श्रोताओं को अलग करें

आपके फायरबेस डेटाबेस संदर्भ पर off() विधि को कॉल करके कॉलबैक हटा दिए जाते हैं।

आप एक श्रोता को off() के पैरामीटर के रूप में पास करके हटा सकते हैं। बिना किसी तर्क के स्थान पर कॉल करना off() उस स्थान के सभी श्रोताओं को हटा देता है।

माता-पिता श्रोता पर कॉल करना off() अपने बच्चे के नोड्स पर पंजीकृत श्रोताओं को स्वचालित रूप से नहीं हटाता है; कॉलबैक को हटाने के लिए किसी भी बाल श्रोताओं को off() भी कहा जाना चाहिए।

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

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

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

Web modular API

import { getDatabase, ref, runTransaction } from "firebase/database";

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web namespaced API

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

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

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

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

Web modular API

function addStar(uid, key) {
  import { getDatabase, increment, ref, update } from "firebase/database";
  const dbRef = ref(getDatabase());

  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = increment(1);
  update(dbRef, updates);
}

Web namespaced API

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

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

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

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

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

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

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

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

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

अगले कदम