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

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

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

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

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

  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 से जोड़कर पुनर्प्राप्त किया जाता है। श्रोता को डेटा की प्रारंभिक स्थिति के लिए एक बार ट्रिगर किया जाता है और फिर जब भी डेटा बदलता है।

बुनियादी लेखन संचालन

बुनियादी लेखन कार्यों के लिए, आप डेटा को एक निर्दिष्ट संदर्भ में सहेजने के लिए, उस पथ पर किसी भी मौजूदा डेटा को प्रतिस्थापित करने के लिए 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() पर कॉल करते हैं तो स्नैपशॉट false लौट आएगा और जब आप val() पर कॉल करेंगे तो वह null

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

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() सर्वर मान वापस करने में असमर्थ है, तो क्लाइंट स्थानीय स्टोरेज कैश की जांच करेगा और यदि मान अभी भी नहीं मिला है तो एक त्रुटि लौटाएगा।

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 पर दूसरी प्रविष्टि बनाने के लिए किया जा सकता है।

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

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

यदि आप जानना चाहते हैं कि आपका डेटा कब प्रतिबद्ध किया गया है, तो आप एक पूर्णता कॉलबैक जोड़ सकते हैं। 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 प्राप्त करें

यह जानने के लिए कि आपका डेटा फ़ायरबेस रीयलटाइम डेटाबेस सर्वर के लिए कब प्रतिबद्ध है, आप 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);
}

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

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

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

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

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

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

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

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

अगले कदम