Web'de Veri Okuma ve Yazma

(İsteğe bağlı) Firebase Local Emulator Suite ile prototip oluşturun ve test edin

Uygulamanızın Realtime Database'den nasıl okuduğu ve Realtime Database'e nasıl yazıldığı hakkında konuşmadan önce, Realtime Database işlevinin prototipini oluşturmak ve test etmek için kullanabileceğiniz Firebase Local Emulator Suite adlı araçlardan bahsedelim. 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 çok iyi bir fikir olabilir.

Realtime Database emülatörü, Local Emulator Suite'in bir parçasıdır. Bu paket, uygulamanızın emüle edilmiş veritabanı içeriğiniz ve yapılandırmanızın yanı sıra isteğe bağlı olarak emüle edilen proje kaynaklarınızla (işlevler, diğer veritabanları ve güvenlik kuralları) etkileşimde bulunmasını sağlar.

Realtime Database emülatörünün kullanımı yalnızca birkaç adımdan oluşur:

  1. Emülatöre bağlanmak için uygulamanızın test yapılandırmasına bir kod satırı ekleme.
  2. Yerel proje dizininizin kök dizininden firebase emulators:start komutunu çalıştırın.
  3. Normalde olduğu gibi bir Realtime Database platform SDK'sı veya Realtime Database REST API kullanarak uygulamanızın prototip kodundan çağrı yapma.

Realtime Database ve Cloud Functions'ı içeren adım adım açıklamalı 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ı alma

Veritabanından veri okumak veya yazmak için firebase.database.Reference örneğinin olması gerekir:

Web modüler API

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web ad alanı API'si

var database = firebase.database();

Verileri yazma

Bu belgede, veri almayla ilgili temel bilgilerin yanı sıra Firebase verilerinin nasıl sıralanacağı ve filtreleneceği açıklanmaktadır.

Firebase verileri, firebase.database.Reference öğesine eşzamansız işleyici eklenerek alınır. İşleyici, verilerin ilk durumu için bir kez ve veriler her değiştiğinde bir kez daha tetiklenir.

Temel yazma işlemleri

Temel yazma işlemlerinde, verileri belirtilen bir referansa kaydetmek ve söz konusu yoldaki mevcut tüm verileri değiştirmek için set() kullanabilirsiniz. Örneğin, bir sosyal blog uygulaması set() adresine sahip bir kullanıcıyı aşağıdaki şekilde ekleyebilir:

Web modüler 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 ad alanı API'si

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

set() kullanıldığında, tüm alt düğümler de dahil olmak üzere belirtilen konumdaki verilerin üzerine yazılır.

Verileri okuma

Değer etkinliklerine göz atın

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için onValue() öğesini kullanarak etkinlikleri gözlemleyin. Etkinlik sırasında mevcut oldukları için belirli bir yoldaki içeriklerin statik anlık görüntülerini okumak için bu etkinliği kullanabilirsiniz. Bu yöntem, işleyici eklendiğinde bir kez ve alt öğeler dahil olmak üzere veriler her değiştiğinde tetiklenir. Etkinlik geri çağırmasına, alt veriler de dahil olmak üzere söz konusu konumdaki tüm verileri içeren bir anlık görüntü iletilir. Veri yoksa anlık görüntü, exists() çağrısı yaptığınızda false, val() çağrısı yaptığınızda ise null değerini döndürür.

Aşağıdaki örnekte, bir yayının yıldız sayısını veritabanından alan bir sosyal blog uygulaması gösterilmektedir:

Web modüler 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 ad alanı API'si

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

İşleyici, etkinlik sırasında veritabanında belirtilen konumda verileri içeren bir snapshot alır. snapshot içindeki verileri val() yöntemini kullanarak alabilirsiniz.

Verileri bir kez oku

get() ile verileri bir kez okuma

SDK, uygulamanızın online veya çevrimdışı olması fark etmeksizin veritabanı sunucularıyla etkileşimleri yönetecek şekilde tasarlanmıştır.

Genel olarak, verilerde arka uçtaki güncellemeler hakkında bildirim almak amacıyla verileri okumak için yukarıda açıklanan değer etkinliği tekniklerini kullanmanız gerekir. Dinleyici teknikleri, kullanımınızı ve faturalandırmanızı azaltır, kullanıcılarınıza internette ve çevrimdışıyken en iyi deneyimi sunmak için optimize edilmiştir.

Verilere yalnızca bir kez ihtiyaç duyarsanız veritabanındaki verilerin anlık görüntüsünü almak için get() kullanabilirsiniz. get(), herhangi bir nedenle sunucu değerini döndüremezse istemci, yerel depolama önbelleğini kontrol eder ve değer hâlâ bulunamazsa hata döndürür.

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

Web modüler 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 ad alanı API'si

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 okuma

Bazı durumlarda, sunucuda güncellenmiş değeri kontrol etmek yerine yerel önbellekteki değerin hemen döndürülmesini isteyebilirsiniz. Bu gibi durumlarda, yerel disk önbelleğinden verileri hemen almak için once() kullanabilirsiniz.

Bu, yalnızca bir kez yüklenmesi gereken ve sık sık değişmesi beklenmeyen veya etkin dinleme gerektirmesi beklenen veriler için faydalıdır. Örneğin, önceki örneklerde bahsedilen blog uygulaması, yeni bir yayın yazmaya başlayan kullanıcının profilini yüklemek için şu yöntemi kullanır:

Web modüler 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 ad alanı API'si

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 aynı anda bir düğümün belirli alt öğelerine yazmak için update() yöntemini kullanın.

update() çağrısı yapılırken, anahtarın yolunu belirterek alt düzey alt değerleri güncelleyebilirsiniz. Veriler daha iyi ölçeklendirmek için birden fazla konumda depolanıyorsa veri yayma yöntemini kullanarak bu verilerin tüm örneklerini güncelleyebilirsiniz.

Örneğin, bir sosyal blog uygulaması bir yayın oluşturabilir ve aşağıdaki gibi bir kod kullanarak bu yayını aynı anda en son etkinlik feed'i ve yayın yapan kullanıcının etkinlik feed'iyle güncelleyebilir:

Web modüler 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 ad alanı API'si

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 örnekte, /posts/$postid alanındaki tüm kullanıcılar için yayınları içeren düğümde bir yayın oluşturmak ve aynı anda anahtarı almak üzere push() kullanılmaktadır. Bu anahtar daha sonra kullanıcının /user-posts/$userid/$postid adresindeki yayınlarında ikinci bir giriş oluşturmak için kullanılabilir.

Bu yolları kullanarak, tek bir update() çağrısı yaparak JSON ağacındaki birden fazla konumda eş zamanlı güncellemeler yapabilirsiniz (örneğin, bu örneğin yeni yayını her iki konumda da nasıl oluşturduğu). Bu şekilde yapılan eş zamanlı güncellemeler son derece önemlidir: ya tüm güncellemeler başarılı olur ya da başarısız olur.

Tamamlama Geri Çağırması Ekle

Verilerinizin ne zaman kaydedildiğini öğrenmek istiyorsanız tamamlama geri çağırması ekleyebilirsiniz. Hem set() hem de update(), yazma işlemi veritabanına yapıldığında çağrılan isteğe bağlı tamamlama geri çağırmasını alır. Çağrı başarısız olursa geri çağırma işlevine hatanın neden oluştuğunu belirten bir hata nesnesi iletilir.

Web modüler 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 ad alanı API'si

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

Verileri silin

Verileri silmenin en basit yolu, söz konusu verilerin konumuna referans vererek remove() öğesini çağırmaktır.

set() veya update() gibi başka bir yazma işlemi için null değerini belirterek de silme işlemini yapabilirsiniz. Bu tekniği, tek bir API çağrısında birden çok alt öğeyi silmek için update() ile kullanabilirsiniz.

Promise alın

Verilerinizin Firebase Realtime Database sunucusuna ne zaman kaydedildiğini öğrenmek için Promise kullanabilirsiniz. Hem set() hem de update(), yazma işleminin veritabanına ne zaman uygulandığını öğrenmek için kullanabileceğiniz bir Promise döndürebilir.

Dinleyicileri ayır

Geri çağırma işlevleri, Firebase veritabanı referansınızda off() yöntemi çağrılarak kaldırılır.

Tek bir işleyiciyi off() öğesine parametre olarak ileterek kaldırabilirsiniz. off() uygulamasının konumda bağımsız değişken olmadan çağrılması, söz konusu konumdaki tüm dinleyicileri kaldırır.

Bir üst işleyicide off() çağrısı yapıldığında, alt düğümlerde kayıtlı işleyiciler otomatik olarak kaldırılmaz. Geri çağırmanın kaldırılması için tüm alt işleyicilerde de off() çağrılmalıdır.

Verileri işlem olarak kaydet

Artımlı sayaçlar gibi eşzamanlı değişikliklere göre bozulabilecek verilerle çalışırken işlem işlemi kullanabilirsiniz. Bu işleme bir güncelleme işlevi ve isteğe bağlı bir tamamlama geri çağırması ekleyebilirsiniz. Güncelleme işlevi, verilerin mevcut durumunu bağımsız değişken 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 tekrar çağrılır ve yazma işlemi yeniden denenir.

Örneğin, örnek sosyal blog uygulaması uygulamasında, kullanıcıların yayınlara yıldız eklemesine ve yıldızlarını kaldırmasına ve bir yayının kaç yıldız aldığını aşağıdaki şekilde takip etmesine olanak tanıyabilirsiniz:

Web modüler 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 ad alanı API'si

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şlem kullanmak, birden çok kullanıcının aynı yayına aynı anda yıldız göstermesi veya istemcinin eski verileri varsa yıldız sayılarının yanlış belirlenmesini önler. İşlem reddedilirse sunucu geçerli değeri istemciye geri gönderir ve istemci, güncellenmiş değerle işlemi tekrar çalıştırır. Bu işlem, işlem kabul edilene veya siz iptal edene kadar tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım örneğinde veritabanına iki değer yazıyoruz: yayına yıldız veren/yıldızı kaldıran kullanıcının kimliği ve artan yıldız sayısı. Kullanıcının yayına yıldız eklediğini zaten biliyorsak işlem yerine atomik artırma işlemi kullanabiliriz.

Web modüler 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 ad alanı API'si

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şlemini kullanmaz. Bu nedenle, çakışan bir güncelleme olduğunda otomatik olarak yeniden çalıştırılmaz. Bununla birlikte, artırma işlemi doğrudan veritabanı sunucusunda gerçekleştiği için çakışma olasılığı yoktur.

Kullanıcının daha önce yıldız eklediği bir yayına yıldız eklemesi gibi uygulamaya özgü çakışmaları tespit etmek ve reddetmek istiyorsanız bu kullanım alanı için özel güvenlik kuralları yazmanız gerekir.

Verilerle çevrimdışı çalışma

İstemcinin ağ bağlantısı kesilirse uygulamanız düzgün şekilde çalışmaya devam eder.

Firebase veritabanına bağlı her müşteri, tüm etkin verilerin kendi dahili sürümlerini korur. Veriler yazıldığında, öncelikle bu yerel sürüme yazılır. Firebase istemcisi daha sonra bu verileri uzak veritabanı sunucuları ve diğer istemcilerle "en iyi çaba" temelinde senkronize eder.

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

Bağlantı yeniden kurulduktan sonra uygulamanız, uygun etkinlik grubunu alır. Böylece, istemci herhangi bir özel kod yazmak zorunda kalmadan mevcut sunucu durumuyla senkronize edilir.

Online ve çevrimdışı özellikler hakkında daha fazla bilgi bölümünde çevrimdışı davranış hakkında daha fazla bilgi vereceğiz.

Sonraki adımlar