Veri Okuma ve Yazma

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

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

Uygulamanızın Realtime Database'den nasıl okuduğundan ve ona yazdığından bahsetmeden önce, Realtime Database işlevselliğini prototiplemek ve test etmek için kullanabileceğiniz bir dizi araç tanıtalım: Firebase Emulator Suite. Farklı veri modelleri 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ış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 Emulator Suite'in bir parçasıdır.emulator_suite_short

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 .
  3. Her zamanki gibi bir Realtime Database platformu SDK'sını veya Realtime Database REST API'sini kullanarak uygulamanızın prototip kodundan çağrı yapma.

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

Bir Veritabanı Referansı Alın

Veritabanından veri okumak veya yazmak için bir DatabaseReference örneğine ihtiyacınız vardır:

DatabaseReference ref = FirebaseDatabase.instance.ref();

Veri yaz

Bu belge, Firebase verilerini okuma ve yazmayla ilgili temel bilgileri kapsar.

Firebase verileri bir DatabaseReference yazılır ve referans tarafından yayılan olayları bekleyerek veya dinleyerek alınır. Olaylar, verilerin ilk durumu için bir kez ve veriler her değiştiğinde tekrar yayınlanır.

Temel yazma işlemleri

Temel yazma işlemleri için, o yoldaki mevcut verileri değiştirerek belirli bir referansa veri kaydetmek için set() 'i kullanabilirsiniz. Aşağıdaki türlere bir başvuru ayarlayabilirsiniz: String , boolean , int , double , Map , List .

Örneğin, set() ile bir kullanıcıyı aşağıdaki gibi ekleyebilirsiniz:

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

await ref.set({
  "name": "John",
  "age": 18,
  "address": {
    "line1": "100 Mountain View"
  }
});

set() 'i bu şekilde kullanmak, herhangi bir alt düğüm de dahil olmak üzere belirtilen konumdaki verilerin üzerine yazar. Ancak, tüm nesneyi yeniden yazmadan bir alt öğeyi güncelleyebilirsiniz. Kullanıcıların profillerini güncellemelerine izin vermek istiyorsanız, kullanıcı adını aşağıdaki gibi güncelleyebilirsiniz:

DatabaseReference ref = FirebaseDatabase.instance.ref("users/123");

// Only update the name, leave the age and address!
await ref.update({
  "age": 19,
});

update() yöntemi, düğümlere giden bir alt yolu kabul ederek, veritabanındaki birden çok düğümü aynı anda güncellemenize olanak tanır:

DatabaseReference ref = FirebaseDatabase.instance.ref("users");

await ref.update({
  "123/age": 19,
  "123/address/line1": "1 Mountain View",
});

Verileri oku

Değer olaylarını dinleyerek verileri okuyun

Bir yoldaki verileri okumak ve değişiklikleri dinlemek için DatabaseEvent s'yi dinlemek için DatabaseReference onValue özelliğini kullanın.

Verileri, olay zamanında var olduğu için, belirli bir yoldaki verileri okumak için DatabaseEvent kullanabilirsiniz. Bu olay, dinleyici eklendiğinde bir kez tetiklenir ve alt öğeler de dahil olmak üzere veriler her değiştiğinde yeniden tetiklenir. Olayın, alt veriler de dahil olmak üzere o konumdaki tüm verileri içeren bir snapshot özelliği vardır. Veri yoksa, anlık görüntünün exists özelliği false olur ve value özelliği boş olur.

Aşağıdaki örnek, veri tabanından bir gönderinin ayrıntılarını alan bir sosyal blog uygulamasını göstermektedir:

DatabaseReference starCountRef =
        FirebaseDatabase.instance.ref('posts/$postId/starCount');
starCountRef.onValue.listen((DatabaseEvent event) {
    final data = event.snapshot.value;
    updateStarCount(data);
});

Dinleyici, value özelliğinde olay sırasında veritabanında belirtilen konumdaki verileri içeren bir DataSnapshot alır.

Verileri bir kez oku

get() kullanarak bir kez okuyun

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

Genel olarak, arka uçtan verilerde yapılan güncellemelerden haberdar olmak için verileri okumak için yukarıda açıklanan değer olayları tekniklerini kullanmalısınız. Bu teknikler, 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 sunmak için optimize edilmiştir.

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

Aşağıdaki örnek, bir kullanıcının herkese açık kullanıcı adının veritabanından tek seferde alınmasını gösterir:

final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child('users/$userId').get();
if (snapshot.exists) {
    print(snapshot.value);
} else {
    print('No data available.');
}

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

Once() ile verileri bir kez okuyun

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

final event = await ref.once(DatabaseEventType.value);
final username = event.snapshot.value?.username ?? 'Anonymous';

Verileri güncelleme veya silme

Belirli alanları güncelle

Diğer alt düğümlerin üzerine yazmadan bir düğümün belirli çocuklarına 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. Daha iyi ölçeklendirmek için veriler 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şturmak ve aynı anda onu en son etkinlik akışına ve gönderiyi gönderen kullanıcının etkinlik akışına güncellemek isteyebilir. Bunu yapmak için blog uygulaması şöyle bir kod kullanır:

void writeNewPost(String uid, String username, String picture, String title,
        String body) async {
    // A post entry.
    final postData = {
        'author': username,
        'uid': uid,
        'body': body,
        'title': title,
        'starCount': 0,
        'authorPic': picture,
    };

    // Get a key for a new Post.
    final newPostKey =
        FirebaseDatabase.instance.ref().child('posts').push().key;

    // Write the new post's data simultaneously in the posts list and the
    // user's post list.
    final Map<String, Map> updates = {};
    updates['/posts/$newPostKey'] = postData;
    updates['/user-posts/$uid/$newPostKey'] = postData;

    return FirebaseDatabase.instance.ref().update(updates);
}

Bu örnek, /posts/$postid tüm kullanıcılar için gönderileri içeren düğümde bir gönderi oluşturmak ve aynı anda anahtarı ile key almak için push() 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, bu örneğin her iki konumda yeni gönderiyi nasıl oluşturduğu gibi, update() öğesine tek bir çağrıyla JSON ağacındaki birden çok konumda eşzamanlı güncellemeler gerçekleştirebilirsiniz. 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.

Bir tamamlama geri araması ekleyin

Verilerinizin ne zaman kaydedildiğini bilmek istiyorsanız, tamamlama geri aramalarını kaydedebilirsiniz. Hem set() hem de update() , yazma işlemi veritabanına yapıldığında ve çağrı başarısız olduğunda çağrılan başarı ve hata geri çağrılarını ekleyebileceğiniz Future s'yi döndürür.

FirebaseDatabase.instance
    .ref('users/$userId/email')
    .set(emailAddress)
    .then((_) {
        // Data saved successfully!
    })
    .catchError((error) {
        // The write failed...
    });

Verileri sil

Verileri silmenin en basit yolu, o verinin konumuna bir referansta remove() ç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 çok çocuğu silmek için bu tekniği update() ile kullanabilirsiniz.

Verileri işlem olarak kaydedin

Artımlı sayaçlar gibi eşzamanlı değişiklikler tarafından bozulabilecek verilerle çalışırken, bir işlem işleyicisini runTransaction() ileterek bir işlem kullanabilirsiniz. Bir işlem işleyicisi, verilerin mevcut durumunu bir argüman olarak alır ve yazmak istediğiniz yeni istenen 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 gönderilere yıldız eklemesine ve yıldızları kaldırmasına ve bir gönderinin kaç yıldız aldığını aşağıdaki gibi takip etmesine izin verebilirsiniz:

void toggleStar(String uid) async {
  DatabaseReference postRef =
      FirebaseDatabase.instance.ref("posts/foo-bar-123");

  TransactionResult result = await postRef.runTransaction((Object? post) {
    // Ensure a post at the ref exists.
    if (post == null) {
      return Transaction.abort();
    }

    Map<String, dynamic> _post = Map<String, dynamic>.from(post as Map);
    if (_post["stars"] is Map && _post["stars"][uid] != null) {
      _post["starCount"] = (_post["starCount"] ?? 1) - 1;
      _post["stars"][uid] = null;
    } else {
      _post["starCount"] = (_post["starCount"] ?? 0) + 1;
      if (!_post.containsKey("stars")) {
        _post["stars"] = {};
      }
      _post["stars"][uid] = true;
    }

    // Return the new data.
    return Transaction.success(_post);
  });
}

Varsayılan olarak, işlem güncelleme işlevi her çalıştığında olaylar başlatılır, bu nedenle işlevi birden çok kez çalıştırırsanız, ara durumları görebilirsiniz. Bu ara durumları bastırmak için applyLocally false olarak ayarlayabilir ve bunun yerine olaylar oluşturulmadan önce işlemin tamamlanmasını bekleyebilirsiniz:

await ref.runTransaction((Object? post) {
  // ...
}, applyLocally: false);

Bir işlemin sonucu, işlemin gerçekleştirilip gerçekleştirilmediği ve yeni anlık görüntü gibi bilgileri içeren bir TransactionResult olur:

DatabaseReference ref = FirebaseDatabase.instance.ref("posts/123");

TransactionResult result = await ref.runTransaction((Object? post) {
  // ...
});

print('Committed? ${result.committed}'); // true / false
print('Snapshot? ${result.snapshot}'); // DataSnapshot

Bir işlemi iptal etme

Bir işlemi güvenli bir şekilde iptal etmek istiyorsanız, AbortTransactionException oluşturmak için Transaction.abort() öğesini arayın:

TransactionResult result = await ref.runTransaction((Object? user) {
  if (user !== null) {
    return Transaction.abort();
  }

  // ...
});

print(result.committed); // false

Atomik sunucu tarafı artışları

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

void addStar(uid, key) async {
  Map<String, Object?> updates = {};
  updates["posts/$key/stars/$uid"] = true;
  updates["posts/$key/starCount"] = ServerValue.increment(1);
  updates["user-posts/$key/stars/$uid"] = true;
  updates["user-posts/$key/starCount"] = ServerValue.increment(1);
  return FirebaseDatabase.instance.ref().update(updates);
}

Bu kod bir işlem işlemi kullanmaz, bu nedenle çakışan bir güncelleme varsa 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 eklemiş olduğu bir gönderiye yıldız eklemesi gibi uygulamaya özel çakışmaları algılamak ve reddetmek istiyorsanız, bu kullanım durumu için özel güvenlik kuralları yazmalısınız.

Verilerle çevrimdışı çalışın

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

Bir Firebase veritabanına bağlanan her istemci, herhangi bir etkin verinin kendi dahili sürümünü tutar. Veri 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 hemen önce yerel olayları tetikler. Bu, uygulamanızın ağ gecikmesinden veya bağlantıdan bağımsız olarak 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 eşitlenir.

Ç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