Web'de Veri Okuma ve Yazma

(İsteğe bağlı) Firebase Local Emulator Suite ile prototip yapın ve test edin

Uygulamanızın Gerçek Zamanlı Veritabanından nasıl okuduğu ve ona nasıl yazdığı hakkında konuşmadan önce, Gerçek Zamanlı Veritabanı işlevselliğini prototiplemek ve test etmek için kullanabileceğiniz bir dizi aracı tanıtalım: Firebase Local Emulator Suite. Farklı veri modelleri deniyorsanız, güvenlik kurallarınızı optimize ediyorsanız veya arka uçla etkileşim kurmanın en uygun maliyetli yolunu bulmaya çalışıyorsanız, canlı hizmetleri dağıtmadan yerel olarak çalışabilmek harika bir fikir olabilir.

Gerçek Zamanlı Veritabanı öykünücüsü, uygulamanızın öykünülmüş veritabanı içeriğiniz ve yapılandırmanızın yanı sıra isteğe bağlı olarak öykünülmüş proje kaynaklarınızla (işlevler, diğer veritabanları ve güvenlik kuralları) etkileşim kurmasını sağlayan Yerel Öykünücü Paketinin bir parçasıdır.

Gerçek Zamanlı Veritabanı öykünücüsünü kullanmak yalnızca birkaç adımı içerir:

  1. Öykünücüye bağlanmak için uygulamanızın test yapılandırmasına bir kod satırı ekleme.
  2. Yerel proje dizininizin kökünden, firebase emulators:start çalıştırılıyor.
  3. Her zamanki gibi bir Realtime Database platformu SDK'sını kullanarak veya Realtime Database REST API'yi kullanarak uygulamanızın prototip kodundan çağrı yapmak.

Gerçek Zamanlı Veritabanı ve Bulut İşlevlerini içeren ayrıntılı bir kılavuz mevcuttur. Ayrıca Local Emulator Suite tanıtımına da göz atmalısınız.

Veritabanı referansı alın

Veritabanından veri okumak veya yazmak için firebase.database.Reference örneğine ihtiyacınız vardır:

Web modular API

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web namespaced API

var database = firebase.database();

Veri yaz

Bu belge, veri almanın temellerini ve Firebase verilerinin nasıl sıralanıp filtreleneceğini kapsar.

Firebase verileri, firebase.database.Reference dosyasına eşzamansız bir dinleyici eklenerek alınır. Dinleyici, verinin başlangıç ​​durumu için bir kez ve veri değiştiğinde tekrar tetiklenir.

Temel yazma işlemleri

Temel yazma işlemleri için, verileri belirli bir referansa kaydetmek ve o yoldaki mevcut verileri değiştirmek için set() işlevini kullanabilirsiniz. Örneğin bir sosyal blog uygulaması set() ile bir kullanıcıyı aşağıdaki gibi ekleyebilir:

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() işlevini kullanmak, alt düğümler de dahil olmak üzere belirtilen konumdaki verilerin üzerine yazar.

Verileri oku

Değer olaylarını dinleyin

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için olayları gözlemlemek üzere onValue() kullanın. Bu olayı, belirli bir yoldaki içeriklerin statik anlık görüntülerini, olay anında mevcut oldukları şekliyle okumak için kullanabilirsiniz. Bu yöntem, dinleyici eklendiğinde bir kez tetiklenir ve çocuklar da dahil olmak üzere veriler her değiştiğinde tekrar tetiklenir. Olay geri çağrısına, alt veriler de dahil olmak üzere o konumdaki tüm verileri içeren bir anlık görüntü iletilir. Veri yoksa, anlık görüntü, exists() öğesini çağırdığınızda false değerini, val() öğesini çağırdığınızda ise null döndürür.

Aşağıdaki örnek, bir gönderinin yıldız sayısını veritabanından alan bir sosyal blog uygulamasını göstermektedir:

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

Dinleyici, olay anında veritabanında belirtilen konumdaki verileri içeren bir snapshot alır. snapshot görüntüdeki verileri val() yöntemiyle alabilirsiniz.

Verileri bir kez okuyun

Get() ile verileri bir kez okuyun

SDK, uygulamanızın çevrimiçi veya çevrimdışı olmasına bakılmaksızın veritabanı sunucularıyla olan etkileşimleri yönetmek için tasarlanmıştır.

Genel olarak, arka uçtan verilerdeki güncellemelerden haberdar olmak amacıyla verileri okumak için yukarıda açıklanan değer olayı tekniklerini kullanmalısınız. Dinleyici teknikleri, kullanımınızı ve faturalandırmanızı azaltır ve kullanıcılarınıza çevrimiçi ve çevrimdışıyken en iyi deneyimi sunmak için optimize edilmiştir.

Verilere yalnızca bir kez ihtiyacınız varsa, veritabanındaki verilerin anlık görüntüsünü almak için get() komutunu kullanabilirsiniz. Herhangi bir nedenle get() sunucu değerini döndüremezse, istemci yerel depolama önbelleğini araştıracak ve değer hala bulunamazsa bir hata döndürecektir.

get() işlevinin gereksiz kullanımı bant genişliği kullanımını artırabilir ve performans kaybına yol açabilir; bu da yukarıda gösterildiği gibi gerçek zamanlı bir dinleyici kullanılarak önlenebilir.

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

Verileri bir gözlemciyle bir kez okuyun

Bazı durumlarda, sunucuda güncelleştirilmiş bir değer olup olmadığını kontrol etmek yerine, yerel önbellekteki değerin hemen döndürülmesini isteyebilirsiniz. Bu durumlarda verileri yerel disk önbelleğinden hemen almak için once() kullanabilirsiniz.

Bu, yalnızca bir kez yüklenmesi gereken ve sık sık değişmesi beklenmeyen veya aktif dinleme gerektirmeyen veriler için kullanışlıdır. Örneğin, önceki örneklerdeki blog uygulaması, yeni bir gönderi yazmaya başladığında kullanıcının profilini yüklemek için bu yöntemi kullanır:

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';
  // ...
});

Verileri güncelleme veya silme

Belirli alanları güncelle

Diğer alt düğümlerin üzerine yazmadan bir düğümün belirli alt öğelerine aynı anda yazmak için update() yöntemini kullanın.

update() öğesini çağırırken, anahtar için bir yol belirterek alt düzey alt değerleri güncelleyebilirsiniz. Veriler daha iyi ölçeklendirmek için birden fazla konumda depolanıyorsa, veri yayma özelliğini kullanarak bu verilerin tüm örneklerini güncelleyebilirsiniz.

Örneğin, bir sosyal blog uygulaması bir gönderi oluşturabilir ve aşağıdaki gibi bir kod kullanarak bunu eş zamanlı olarak en son etkinlik akışına ve gönderi paylaşan kullanıcının etkinlik akışına güncelleyebilir:

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

Bu örnek, düğümde /posts/$postid adresindeki tüm kullanıcılar için gönderiler içeren bir gönderi oluşturmak ve aynı anda anahtarı almak için push() işlevini kullanır. Anahtar daha sonra kullanıcının /user-posts/$userid/$postid adresindeki gönderilerinde ikinci bir giriş oluşturmak için kullanılabilir.

Bu yolları kullanarak, JSON ağacındaki birden çok konuma update() çağrısıyla eş zamanlı güncellemeler gerçekleştirebilirsiniz; örneğin bu örneğin her iki konumda da yeni gönderiyi nasıl oluşturduğu gibi. Bu şekilde yapılan eşzamanlı güncellemeler atomiktir: ya tüm güncellemeler başarılı olur ya da tüm güncellemeler başarısız olur.

Tamamlama Geri Araması Ekleme

Verilerinizin ne zaman kaydedildiğini bilmek istiyorsanız tamamlama geri araması ekleyebilirsiniz. Hem set() hem de update() veri tabanına yazma işlemi tamamlandığında çağrılan isteğe bağlı bir tamamlama geri çağrısını alır. Çağrı başarısız olursa, geri çağrıya hatanın neden oluştuğunu belirten bir hata nesnesi iletilir.

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

Verileri sil

Verileri silmenin en basit yolu, söz konusu verinin konumuna ilişkin bir referans üzerinden remove() işlevini çağırmaktır.

set() veya update() gibi başka bir yazma işleminin değeri olarak null belirterek de silebilirsiniz. Tek bir API çağrısında birden fazla alt öğeyi silmek için bu tekniği update() ile kullanabilirsiniz.

Bir Promise Al

Verilerinizin Firebase Gerçek Zamanlı Veritabanı sunucusuna ne zaman kaydedileceğini bilmek için Promise kullanabilirsiniz. Hem set() hem de update() yazma işleminin veritabanına ne zaman kaydedildiğini bilmek için kullanabileceğiniz bir Promise döndürebilir.

Dinleyicileri ayırın

Firebase veritabanı referansınızda off() yöntemi çağrılarak geri aramalar kaldırılır.

Tek bir dinleyiciyi parametre olarak off() öğesine ileterek kaldırabilirsiniz. Bağımsız değişken olmadan konuma off() çağrısı yapmak, o konumdaki tüm dinleyicileri kaldırır.

Bir ana dinleyicide off() işlevinin çağrılması, onun alt düğümlerinde kayıtlı dinleyicileri otomatik olarak kaldırmaz; Geri aramayı kaldırmak için off() işlevi tüm alt dinleyicilerde de çağrılmalıdır.

Verileri işlem olarak kaydet

Artan sayaçlar gibi eş zamanlı değişiklikler nedeniyle bozulabilecek verilerle çalışırken işlem işlemini kullanabilirsiniz. Bu işleme bir güncelleme işlevi ve isteğe bağlı bir tamamlama geri çağrısı verebilirsiniz. Güncelleme fonksiyonu verinin mevcut durumunu argüman olarak alır ve yazmak istediğiniz yeni durumu döndürür. Yeni değeriniz başarıyla yazılmadan önce başka bir istemci konuma yazarsa, güncelleme işleviniz yeni geçerli değerle yeniden çağrılır ve yazma işlemi yeniden denenir.

Örneğin, örnek sosyal blog uygulamasında, kullanıcıların gönderilere yıldız eklemesine ve yıldızları kaldırmasına ve bir gönderinin kaç yıldız aldığını takip etmesine aşağıdaki şekilde izin verebilirsiniz:

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

Bir işlemin kullanılması, birden fazla kullanıcının aynı gönderiye aynı anda yıldız vermesi veya istemcinin eski verileri olması durumunda yıldız sayımlarının hatalı olmasını önler. İşlem reddedilirse, sunucu mevcut değeri istemciye döndürür ve istemci, işlemi güncellenmiş değerle yeniden çalıştırır. Bu, işlem kabul edilene veya siz işlemi iptal edene kadar tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım durumunda veritabanına iki değer yazıyoruz: gönderiye yıldız veren/yıldızını kaldıran kullanıcının kimliği ve artan yıldız sayısı. Kullanıcının gönderiye başrol oynadığını zaten biliyorsak, işlem yerine atomik artış işlemini kullanabiliriz.

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

Bu kod bir işlem işlemi kullanmadığından, çakışan bir güncelleme olması durumunda otomatik olarak yeniden çalıştırılmaz. Ancak artırma işlemi doğrudan veritabanı sunucusunda gerçekleştiği için çakışma olasılığı yoktur.

Bir kullanıcının daha önce yıldız eklediği bir gönderiye yıldız eklemesi gibi uygulamaya özel çakışmaları tespit etmek ve reddetmek istiyorsanız, o kullanım durumu için özel güvenlik kuralları yazmalısınız.

Verilerle çevrimdışı çalışma

Bir istemcinin ağ bağlantısını kaybederse uygulamanız düzgün çalışmaya devam edecektir.

Firebase veritabanına bağlı her istemci, tüm etkin verilerin kendi dahili sürümünü korur. Veriler yazıldığında öncelikle bu yerel versiyona yazılır. Firebase istemcisi daha sonra bu verileri uzak veritabanı sunucularıyla ve diğer istemcilerle "en iyi çabayı" esas alarak senkronize eder.

Sonuç olarak, veritabanına yapılan tüm yazma işlemleri, sunucuya herhangi bir veri yazılmadan önce yerel olayları hemen tetikler. Bu, uygulamanızın ağ gecikmesine veya bağlantısına bakılmaksızın yanıt vermeye devam edeceği anlamına gelir.

Bağlantı yeniden kurulduğunda uygulamanız uygun olay kümesini alır, böylece istemci herhangi bir özel kod yazmak zorunda kalmadan mevcut sunucu durumuyla senkronize edilir.

Çevrimiçi ve çevrimdışı yetenekler hakkında daha fazla bilgi edinin bölümünde çevrimdışı davranış hakkında daha fazla konuşacağız.

Sonraki adımlar