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 ile nasıl okuma ve yazma yaptığından bahsetmeden önce, Realtime Database işlevinin prototipini oluşturmak ve test etmek için kullanabileceğiniz bir dizi araçtan bahsedelim: Firebase Local Emulator Suite. Farklı veri modellerini deniyor, güvenlik kurallarınızı optimize ediyor veya arka uçla etkileşim kurmanın en uygun maliyetli yolunu bulmaya çalışıyorsanız canlı hizmetleri dağıtmadan yerel olarak çalışmak iyi bir fikir olabilir.

Realtime Database emülatörü, Local Emulator Suite'nin bir parçasıdır. Bu emülatör, uygulamanızın emülasyonu yapılan veritabanı içeriğiniz ve yapılandırmanızın yanı sıra isteğe bağlı olarak emülasyonu yapılan 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ü kullanmak için yalnızca birkaç adım yeterlidir:

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

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

Veritabanı referansı alma

Veritabanından veri okumak veya veritabanına veri 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();

Verileri yazma

Bu belgede, veri alma ve Firebase verilerini sıralayıp filtreleme ile ilgili temel bilgiler yer almaktadır.

Firebase verileri, firebase.database.Reference öğesine eşzamansız bir dinleyici eklenerek 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 set() kullanarak verileri belirtilen bir referansa kaydedebilir ve bu yoldaki mevcut verileri değiştirebilirsiniz. Ö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 de 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() kullanarak etkinlikleri gözlemleyin. Bu etkinliği, belirli bir yoldaki içeriklerin statik anlık görüntülerini, etkinliğin gerçekleştiği andaki halleriyle okumak için kullanabilirsiniz. Bu yöntem, dinleyici eklendiğinde bir kez ve alt öğeler de dahil olmak üzere veriler her değiştiğinde tekrar tetiklenir. Etkinlik geri çağırma işlevine, alt veriler de dahil olmak üzere ilgili konumdaki tüm verileri içeren bir anlık görüntü iletilir. Veri yoksa anlık görüntü, exists() yöntemini çağırdığınızda false, val() yöntemini çağırdığınızda ise null değerini döndürür.

Aşağıdaki örnekte, bir gönderinin yıldız sayısını veritabanından alan bir sosyal blog uygulaması 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);
});

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

Verileri bir kez okuma

get() ile verileri bir kez okuma

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

Genellikle, arka uçtan gelen verilerle ilgili 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 çevrimiçi ve çevrimdışı olduklarında en iyi deneyimi sunacak şekilde 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() kullanabilirsiniz. get() herhangi bir nedenle sunucu değerini döndüremezse istemci, yerel depolama önbelleğini inceler ve değer hâlâ bulunamazsa bir hata döndürür.

get() yönteminin gereksiz 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ı bir 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);
});

Gözlemci ile verileri bir kez okuma

Bazı durumlarda, sunucuda güncellenmiş 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 yöntem, 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 yayın 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() yöntemini çağırırken anahtar için bir yol belirterek alt düzey alt değerleri güncelleyebilirsiniz. Veriler daha iyi ölçeklendirme 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 aynı anda aşağıdaki gibi bir kod kullanarak yayını son etkinlik feed'ine ve yayınlayan kullanıcının etkinlik feed'ine 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ılar için yayınları içeren düğümde bir yayın oluşturmak ve aynı anda anahtarı almak için push() kullanılır. 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, JSON ağacındaki birden fazla konumda aynı anda güncelleme yapmak için update() yöntemini tek bir kez çağırabilirsiniz. Bu örnekte, yeni yayının her iki konumda da nasıl oluşturulduğu gösterilmektedir. Bu şekilde yapılan eşzamanlı güncellemeler atomiktir: Güncellemelerin ya hepsi başarılı olur ya da hepsi başarısız olur.

Tamamlama geri çağırma işlevi ekleme

Verilerinizin ne zaman kaydedildiğini öğrenmek istiyorsanız bir tamamlama geri çağırma işlevi ekleyebilirsiniz. Hem set() hem de update(), yazma işlemi veritabanına uygulandığında çağrılan isteğe bağlı bir tamamlama geri çağırma işlevi alır. Çağrı 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 kolay yolu, verilerin konumuna referans vererek remove() yöntemini çağırmaktır.

set() veya update() gibi başka bir yazma işlemi için değer 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 kaydedildiğini öğrenmek için Promise kullanabilirsiniz. Hem set() hem de update(), yazma işleminin veritabanına ne zaman kaydedildiğini öğrenmek için kullanabileceğiniz bir Promise döndürebilir.

Dinleyicileri ayırma

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

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

Üst dinleyicide off() yöntemini çağırmak, alt düğümlerinde kayıtlı dinleyicileri otomatik olarak kaldırmaz. Geri çağırmayı kaldırmak için alt dinleyicilerde de off() yönteminin çağrılması gerekir.

Verileri işlem olarak kaydetme

Artımlı sayaçlar gibi eşzamanlı değişiklikler nedeniyle bozulabilecek verilerle çalışırken işlem operasyonu 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, sosyal blog uygulaması örneğinde kullanıcıların yayınlara yıldız ekleyip kaldırmasına ve bir yayının kaç yıldız aldığını aşağıdaki gibi takip etmesine izin verebilirsiniz:

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ının aynı yayına aynı anda yıldız vermesi veya istemcinin eski verilere sahip olması durumunda yıldız sayılarının yanlış olmasını önler. İşlem reddedilirse sunucu, mevcut değeri istemciye döndürür. İstemci de işlemi güncellenmiş değerle tekrar çalıştırır. Bu işlem, işlem kabul edilene veya siz işlemi iptal edene kadar tekrarlanır.

Atomik sunucu tarafı artışları

Yukarıdaki kullanım alanında veritabanına iki değer yazıyoruz: yayına yıldız ekleyen/yıldızı kaldıran kullanıcının kimliği ve artırılan 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

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 kodda işlem operasyonu kullanılmadığından, çakışan bir güncelleme olduğunda 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.

Kullanıcının daha önce yıldız eklediği bir yayına tekrar yıldız eklemesi gibi uygulamaya özel çakışmaları tespit edip 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 istemci, etkin verilerin kendi dahili sürümünü tutar. Veriler yazıldığında önce 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 sayede uygulamanız, ağ gecikmesi veya bağlantı durumundan bağımsız olarak her zaman yanıt verebilir.

Bağlantı yeniden kurulduktan sonra uygulamanız, istemcinin mevcut sunucu durumuyla senkronize olması için uygun etkinlik grubunu alır. Bu işlem için özel kod yazmanız gerekmez.

Çevrimdışı davranış hakkında daha fazla bilgiyi Online ve çevrimdışı özellikler hakkında daha fazla bilgi bölümünde bulabilirsiniz.

Sonraki adımlar