(ज़रूरी नहीं) Firebase लोकल एम्युलेटर सुइट की मदद से प्रोटोटाइप बनाएं और टेस्ट करें
आपका ऐप्लिकेशन रीयलटाइम डेटाबेस से कैसे डेटा लेता है और उसमें क्या लिखा जाता है, इस बारे में बात करने से पहले, आइए ऐसे टूल के बारे में बताते हैं जिनका इस्तेमाल करके, रीयलटाइम डेटाबेस के काम करने के प्रोटोटाइप और की जांच की जा सकती है: Firebase लोकल एम्युलेटर सुइट. अगर अलग-अलग डेटा मॉडल आज़माए जा रहे हैं, सुरक्षा के नियमों को ऑप्टिमाइज़ किया जा रहा है या बैक-एंड से इंटरैक्ट करने का सबसे किफ़ायती तरीका खोजा जा रहा है, तो लाइव सेवाओं को डिप्लॉय किए बिना, स्थानीय तौर पर काम करना अच्छा रहेगा.
रीयल टाइम डेटाबेस एम्युलेटर, Local Emulator Suite का हिस्सा होता है. इससे आपका ऐप्लिकेशन, एम्युलेट किए गए डेटाबेस के कॉन्टेंट और कॉन्फ़िगरेशन से इंटरैक्ट कर पाता है. साथ ही, वह एम्युलेट किए गए प्रोजेक्ट के संसाधनों (फ़ंक्शन, दूसरे डेटाबेस, और सुरक्षा के नियम) से भी इंटरैक्ट करता है.
रीयलटाइम डेटाबेस एम्युलेटर का इस्तेमाल करने के लिए, आपको कुछ ही चरण पूरे करने होंगे:
- एम्युलेटर से कनेक्ट करने के लिए, अपने ऐप्लिकेशन के टेस्ट कॉन्फ़िगरेशन में कोड की एक लाइन जोड़ना.
- आपकी लोकल प्रोजेक्ट डायरेक्ट्री के रूट से,
firebase emulators:start
पर चल रहा है. - हमेशा की तरह, रीयलटाइम डेटाबेस प्लैटफ़ॉर्म एसडीके का इस्तेमाल करके या रीयलटाइम डेटाबेस REST API का इस्तेमाल करके, अपने ऐप्लिकेशन के प्रोटोटाइप कोड से कॉल करना.
रीयल टाइम डेटाबेस और Cloud Functions के बारे में ज़्यादा जानकारी उपलब्ध है. आपको लोकल एम्युलेटर सुइट के बारे में जानकारी भी देखनी चाहिए.
डेटाबेस के बारे में जानकारी पाएं
डेटाबेस से डेटा पढ़ने या उसमें बदलाव करने के लिए, आपके पास 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()
और null
को कॉल किया जाएगा, तब स्नैपशॉट false
के साथ आपको val()
कॉल करेगा.
नीचे दिए गए उदाहरण में सोशल ब्लॉगिंग ऐप्लिकेशन के बारे में बताया गया है, जिसमें डेटाबेस से किसी पोस्ट की स्टार काउंट की जानकारी हासिल की गई है:
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() की मदद से डेटा को एक बार पढ़ना
SDK टूल को डेटाबेस सर्वर के साथ इंटरैक्शन को मैनेज करने के लिए डिज़ाइन किया गया है. इससे कोई फ़र्क़ नहीं पड़ता कि आपका ऐप्लिकेशन ऑनलाइन है या ऑफ़लाइन.
आम तौर पर, बैकएंड से डेटा के अपडेट की सूचना पाने के लिए, आपको ऊपर बताई गई वैल्यू इवेंट तकनीकों का इस्तेमाल करना चाहिए. लिसनर की तकनीक आपके इस्तेमाल और बिलिंग को कम करती है. साथ ही, इन्हें आपके उपयोगकर्ताओं को ऑनलाइन और ऑफ़लाइन होने पर, बेहतरीन अनुभव देने के लिए ऑप्टिमाइज़ किया गया है.
अगर आपको सिर्फ़ एक बार डेटा की ज़रूरत है, तो 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()
को कॉल किया जाए.
वैल्यू के तौर पर null
को तय करके भी मिटाया जा सकता है.
जैसे, set()
या update()
. इस तकनीक का इस्तेमाल update()
के साथ करके, एक एपीआई कॉल में एक से ज़्यादा चिल्ड्रेन की जानकारी मिटाने के लिए किया जा सकता है.
Promise
पाएं
यह जानने के लिए कि आपका डेटा, Firebase रीयल टाइम डेटाबेस सर्वर से कब जुड़ा होता है, 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 क्लाइंट उस डेटा को रिमोट डेटाबेस सर्वर के साथ और अन्य क्लाइंट के साथ "बेहतर तरीके से" सिंक करता है.
इस वजह से, सर्वर पर कोई भी डेटा लिखे जाने से पहले, डेटाबेस में मौजूद सभी डेटा, लोकल इवेंट को ट्रिगर करता है. इसका मतलब है कि नेटवर्क इंतज़ार का समय या कनेक्टिविटी चाहे जो भी हो, आपका ऐप्लिकेशन रिस्पॉन्सिव बना रहता है.
कनेक्टिविटी फिर से इंस्टॉल होने के बाद, आपके ऐप्लिकेशन को इवेंट का सही सेट मिलता है. इससे क्लाइंट, सर्वर की मौजूदा स्थिति के साथ सिंक हो जाता है. इसके लिए, आपको कोई कस्टम कोड लिखने की ज़रूरत नहीं पड़ती.
ऑनलाइन और ऑफ़लाइन सुविधाओं के बारे में ज़्यादा जानें में हम ऑफ़लाइन व्यवहार के बारे में ज़्यादा जानकारी देंगे.