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

(ज़रूरी नहीं) Firebase Local Emulator Suite की मदद से प्रोटोटाइप बनाना और जांच करना

आपका ऐप्लिकेशन Realtime Database से कैसे पढ़ता है और उसमें कैसे लिखता है, इस बारे में बात करने से पहले, Realtime Database की सुविधाओं के प्रोटोटाइप बनाने और उनकी जांच करने के लिए इस्तेमाल किए जा सकने वाले टूल के बारे में बताते हैं: Firebase Local Emulator Suite. अगर अलग-अलग डेटा मॉडल आज़माए जा रहे हैं, सुरक्षा के नियमों को ऑप्टिमाइज़ किया जा रहा है या बैक-एंड से इंटरैक्ट करने का सबसे किफ़ायती तरीका खोजा जा रहा है, तो लाइव सेवाओं को डिप्लॉय किए बिना, स्थानीय तौर पर काम करना अच्छा रहेगा.

Realtime Database एमुलेटर, Local Emulator Suite का हिस्सा होता है. इससे आपके ऐप्लिकेशन को, एमुलेट किए गए डेटाबेस के कॉन्टेंट और कॉन्फ़िगरेशन के साथ-साथ, एमुलेट किए गए प्रोजेक्ट के रिसॉर्स (फ़ंक्शन, अन्य डेटाबेस, और सुरक्षा नियम) के साथ इंटरैक्ट करने में मदद मिलती है.

Realtime Database एमुलेटर का इस्तेमाल करने के लिए, ये चरण अपनाएं:

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

Realtime Database और Cloud Functions के बारे में ज़्यादा जानकारी वाला वॉकथ्रू उपलब्ध है. आपको Local Emulator Suite के बारे में जानकारी भी देखनी चाहिए.

डेटाबेस का रेफ़रंस पाना

डेटाबेस से डेटा पढ़ने या उसमें डेटा लिखने के लिए, आपके पास firebase.database.Reference का एक इंस्टेंस होना चाहिए:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

डेटा सेव करना

इस दस्तावेज़ में, डेटा को वापस पाने के बुनियादी तरीकों के साथ-साथ, Firebase डेटा को क्रम से लगाने और फ़िल्टर करने का तरीका बताया गया है.

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

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

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

Web

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

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

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

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

लिसनर को एक snapshot मिलता है, जिसमें इवेंट के समय डेटाबेस में बताई गई जगह का डेटा होता है. val() तरीके का इस्तेमाल करके, snapshot में डेटा वापस पाया जा सकता है.

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

get() की मदद से डेटा को एक बार पढ़ना

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

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

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

get() का ग़ैर-ज़रूरी इस्तेमाल करने से बैंडविथ का इस्तेमाल बढ़ सकता है और काम करने की क्षमता में कमी आ सकती है. इसे ऊपर बताए गए रीयल टाइम लिसनर का इस्तेमाल करके रोका जा सकता है.

Web

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

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

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

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

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

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);
}

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

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

प्रोसेस पूरी होने पर कॉलबैक जोड़ना

अगर आपको यह जानना है कि आपका डेटा कब कमिट किया गया है, तो आपके पास 'पूरा होने पर कॉलबैक' जोड़ने का विकल्प है. set() और update(), दोनों में एक वैकल्पिक 'पूरा होने पर कॉलबैक' होता है. इसे तब कॉल किया जाता है, जब डेटाबेस में डेटा डालने की प्रोसेस पूरी हो जाती है. अगर कॉल पूरा नहीं हो पाता है, तो कॉलबैक में गड़बड़ी का एक ऑब्जेक्ट पास किया जाता है. इससे पता चलता है कि कॉल पूरा न हो पाने की वजह क्या है.

Web

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

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 Realtime Database सर्वर पर आपका डेटा कब कमिट किया गया, यह जानने के लिए Promise का इस्तेमाल किया जा सकता है. set() और update(), दोनों एक Promise दिखा सकते हैं. इसका इस्तेमाल यह जानने के लिए किया जा सकता है कि जवाब, डेटाबेस से कब जुड़ा होता है.

लिसनर को अलग करें

कॉलबैक हटाने के लिए, अपने Firebase डेटाबेस रेफ़रंस पर off() तरीके को कॉल करें.

किसी एक लिसनर को off() के लिए पैरामीटर के तौर पर पास करके, उसे हटाया जा सकता है. किसी जगह के लिए off() को बिना किसी आर्ग्युमेंट के कॉल करने पर, उस जगह पर मौजूद सभी दर्शकों को हटा दिया जाता है.

पैरंट लिसनर पर off() को कॉल करने से, इसके चाइल्ड नोड पर रजिस्टर किए गए लिसनर अपने-आप नहीं हटते. कॉलबैक को हटाने के लिए, off() को चाइल्ड लिसनर पर भी कॉल किया जाना चाहिए.

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

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

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

Web

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

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

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

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);
}

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

अगर आपको ऐप्लिकेशन से जुड़े किसी खास विवाद का पता लगाना है और उसे अस्वीकार करना है, जैसे कि कोई उपयोगकर्ता किसी ऐसी पोस्ट पर स्टार का निशान लगाता है जिसे उपयोगकर्ता ने पहले से स्टार का निशान लगाया है, तो इस्तेमाल के उदाहरण के लिए आपको कस्टम सुरक्षा नियम लिखना चाहिए.

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

अगर किसी क्लाइंट का इंटरनेट कनेक्शन बंद हो जाता है, तो आपका ऐप्लिकेशन सही तरीके से काम करता रहेगा.

Firebase डेटाबेस से कनेक्ट हर क्लाइंट, किसी भी चालू डेटा का अपना इंटरनल वर्शन बनाए रखता है. डेटा लिखने पर, वह सबसे पहले इस लोकल वर्शन में लिखा जाता है. इसके बाद, Firebase क्लाइंट उस डेटा को रिमोट डेटाबेस के सर्वर और अन्य क्लाइंट के साथ "बेहतरीन तरीके" से सिंक करता है.

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

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

ऑनलाइन और ऑफ़लाइन सुविधाओं के बारे में ज़्यादा जानें में हम ऑफ़लाइन व्यवहार के बारे में ज़्यादा जानकारी देंगे.

अगले चरण