Web'de Veri Okuma ve Yazma

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

Uygulamanızın Realtime Database'den nasıl veri okuduğu ve yazdığı hakkında konuşmadan önce, Realtime Database işlevini prototip haline getirmek ve test etmek için kullanabileceğiniz bir araç grubu olan Firebase Local Emulator Suite'den bahsedelim. Farklı veri modellerini denemek, güvenlik kurallarınızı optimize etmek veya arka uçla etkileşim kurmanın en uygun maliyetli yolunu bulmak için çalışıyorsanız canlı hizmetler dağıtmadan yerel olarak çalışabilmek iyi bir fikir olabilir.

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

Realtime Database emülatörünü kullanmanın birkaç adımı vardır:

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

Realtime Database ve Cloud Functions ile ilgili ayrıntılı bir adım adım açıklamalı kılavuz mevcuttur. Local Emulator Suite girişine de göz atmanız önerilir.

Veritabanı referansı alma

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

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

Veri yazma

Bu belgede, veri alma ve Firebase verilerini sıralama ve filtrelemeyle ilgili temel bilgiler verilmektedir.

Firebase verileri, bir firebase.database.Reference'ye eşzamansız bir dinleyici ekleyerek alınır. Dinleyici, verilerin ilk durumu için bir kez ve veriler her değiştiğinde tekrar tetiklenir.

Temel yazma işlemleri

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

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() kullanıldığında, alt düğümler dahil olmak üzere belirtilen konumdaki verilerin üzerine yazılır.

Verileri okuma

Değer etkinliklerini dinleme

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için onValue() ile etkinlikleri gözlemleyin. Belirli bir yoldaki içeriklerin anlık görüntülerini etkinlik sırasındaki halleriyle okumak için bu etkinliği kullanabilirsiniz. Bu yöntem, dinleyici eklendiğinde bir kez ve çocuklar dahil veriler her değiştiğinde tekrar tetiklenir. Etkinlik geri çağırma işlevine, alt veriler dahil olmak üzere bu konumdaki tüm verileri içeren bir anlık görüntü iletilir. Veri yoksa anlık görüntü, exists()'u aradığınızda false ve val()'ı aradığınızda null döndürür.

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

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

Dinleyici, etkinlik sırasında veritabanında belirtilen konumdaki verileri içeren bir snapshot alır. val() yöntemiyle snapshot içindeki verileri alabilirsiniz.

Verileri bir kez okuma

get() ile verileri bir kez okuma

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

Genel olarak, arka uçtaki verilerde yapılan güncellemelerden haberdar olmak için verileri okumak üzere yukarıda açıklanan değer etkinliği tekniklerini kullanmanız gerekir. Dinleyici teknikleri, kullanımınızı ve faturalandırmanızı azaltır ve kullanıcılarınıza internete bağlanırken ve internete bağlanmazken en iyi deneyimi sunmak için optimize edilir.

Verilere yalnızca bir kez ihtiyacınız varsa veritabanındaki verilerin anlık görüntüsünü almak için get() işlevini kullanabilirsiniz. get() herhangi bir nedenle sunucu değerini döndüremiyorsa istemci yerel depolama önbelleğini araştırır ve değer hâlâ bulunamazsa hata döndürür.

get()'ün gereksiz kullanımı bant genişliği kullanımını artırabilir ve performans kaybına neden olabilir. Bu durum, yukarıda gösterildiği gibi anlık dinleyici kullanılarak önlenebilir.

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

Verileri gözlemciyle bir kez okuma

Bazı durumlarda, sunucuda güncel bir değer olup olmadığını kontrol etmek yerine yerel önbelleğe ait değerin hemen döndürülmesini isteyebilirsiniz. Bu gibi 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 veya etkin dinleme gerektirmesi beklenmeyen veriler için kullanışlıdır. Örneğin, önceki örneklerdeki blog uygulaması, kullanıcı yeni bir gönderi yazmaya başladığında kullanıcının profilini yüklemek için bu yöntemi kullanır:

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

Verileri güncelleme veya silme

Belirli alanları güncelleme

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

update() çağrısı yaparken anahtar için bir yol belirterek alt düzeydeki alt öğe değerlerini güncelleyebilirsiniz. Veriler daha iyi ölçeklendirme için birden fazla konumda depolanıyorsa veri dağıtımını kullanarak bu verilerin tüm örneklerini güncelleyebilirsiniz.

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

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

Bu örnekte, /posts/$postid adresindeki tüm kullanıcılara ait yayınları içeren bir düğümde yayın oluşturmak ve aynı anda anahtarı almak için push() kullanılır. Bu anahtar, kullanıcının /user-posts/$userid/$postid adresindeki yayınlarında ikinci bir giriş oluşturmak için kullanılabilir.

Bu yolları kullanarak, update() çağrısını tek seferde yaparak JSON ağacındaki birden fazla konumda eşzamanlı güncellemeler yapabilirsiniz. Bu örnekte, yeni yayın her iki konumda da bu şekilde oluşturulur. Bu şekilde yapılan eşzamanlı güncellemeler atomiktir: Tüm güncellemeler başarılı olur veya tüm güncellemeler başarısız olur.

Tamamlama geri çağırma işlevi ekleme

Verilerinizin ne zaman bağlandığını bilmek istiyorsanız tamamlama geri çağırma işlevi ekleyebilirsiniz. Hem set() hem de update(), yazma işlemi veritabanına bağlandığında çağrılan isteğe bağlı bir tamamlama geri çağırma işlevi alır. Arama başarısız olursa geri çağırma işlevine, hatanın nedenini belirten bir hata nesnesi iletilir.

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

Verileri silin

Verileri silmenin en basit yolu, söz konusu verilerin konumuna ait bir referans üzerinde 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.

Promise alın

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

Dinleyicileri kaldırma

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

Tek bir dinleyiciyi off() parametresi olarak ileterek kaldırabilirsiniz. Yerde off() işlevi bağımsız değişken olmadan çağrıldığında, söz konusu konumdaki tüm dinleyiciler kaldırılır.

Üst dinleyicide off() çağrıldığında, alt düğümlerine kayıtlı dinleyiciler otomatik olarak kaldırılmaz. Geri çağırma işlevinin kaldırılması için off(), alt dinleyicilerde de çağrılmalıdır.

Verileri işlem olarak kaydetme

Artımlı sayaçlar gibi eşzamanlı değişiklikler nedeniyle bozulabilen 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ğırma işlevi verebilirsiniz. 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ında kullanıcıların yayınlara yıldız eklemesine ve yıldızları kaldırmasına izin verebilir ve bir yayının aldığı yıldız sayısını aşağıdaki gibi takip edebilirsiniz:

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

İşlem kullanmak, birden fazla kullanıcı aynı anda aynı yayına yıldız atarsa veya istemcide eski veriler varsa yıldız sayılarının yanlış olmasını önler. İşlem reddedilirse sunucu geçerli değeri istemciye döndürür. İstemci de güncellenmiş değerle işlemi tekrar çalıştırır. İşlem kabul edilene veya siz iptal edene kadar bu işlem tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım alanında, veritabanına iki değer yazıyoruz: Gönderiye yıldız ekleyen/yıldız işaretini kaldıran kullanıcının kimliği ve artan yıldız sayısı. Kullanıcının yayını favorilediğini zaten biliyorsak işlem yerine atomik artış işlemi kullanabiliriz.

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

Bu kod bir işlem işlemi kullanmadığından, çakışan bir güncelleme varsa otomatik olarak yeniden çalıştırılmaz. Ancak artma 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ızla işaretlediği bir yayını yıldızla işaretlemesi gibi uygulamaya özgü çakışmaların tespit edilip reddedilmesini istiyorsanız bu kullanım alanı için özel güvenlik kuralları yazmanız gerekir.

Verilerle çevrimdışı çalışma

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

Bir Firebase veritabanına bağlı her istemci, etkin verilerin kendi dahili sürümünü korur. Veriler ilk olarak bu yerel sürüme yazılır. Ardından Firebase istemcisi, bu verileri uzak veritabanı sunucularıyla ve diğer istemcilerle "en iyi çaba" temelinde senkronize eder.

Sonuç olarak, veritabanına yapılan tüm yazma işlemleri, sunucuya veri yazılmadan önce yerel etkinlikleri hemen tetikler. Bu sayede uygulamanız, ağ gecikmesinden veya bağlantıdan etkilenmeden yanıt vermeye devam eder.

Bağlantı yeniden kurulduktan sonra uygulamanız, özel kod yazmak zorunda kalmadan istemcinin mevcut sunucu durumuyla senkronize edilmesi için uygun etkinlik grubunu alır.

Online ve çevrimdışı özellikler hakkında daha fazla bilgi başlıklı makalede çevrimdışı davranış hakkında daha fazla bilgi vereceğiz.

Sonraki adımlar