Firebase'de verileri yapılandırmanın en iyi yolu nedir?


111

Firebase'de yeniyim ve üzerinde verileri yapılandırmanın en iyi yolunun ne olduğunu bilmek istiyorum.

Basit bir örneğim var:

Projemde Başvuru Sahipleri ve Başvurular var. 1 başvuru sahibinin birkaç başvurusu olabilir. Bu 2 nesneyi firebase'de nasıl ilişkilendirebilirim? İlişkisel bir veritabanı gibi çalışıyor mu? Veya yaklaşımın veri tasarımı açısından tamamen farklı olması mı gerekiyor?

Yanıtlar:


137

GÜNCELLEME : Artık verilerin yapılandırılmasına ilişkin bir belge var . Ayrıca, NoSQL veri yapıları hakkındaki bu mükemmel gönderiye bakın .

RDBMS'nin aksine hiyerarşik verilerle ilgili ana sorun, yapabildiğimiz için verileri iç içe yerleştirmenin cazip olmasıdır. Genel olarak, birleştirme ifadeleri ve sorguları olmamasına rağmen verileri bir dereceye kadar normalleştirmek istersiniz (tıpkı SQL'de yaptığınız gibi).

Ayrıca , okuma verimliliğinin önemli olduğu yerlerde normalden uzaklaşmak istersiniz . Bu, tüm büyük ölçekli uygulamalarda (ör. Twitter ve Facebook) kullanılan bir tekniktir ve DRY ilkelerimize aykırı olmasına rağmen, genellikle ölçeklenebilir uygulamaların gerekli bir özelliğidir.

Buradaki esas, okumaları kolaylaştırmak için yazılar üzerinde çok çalışmak istemenizdir. Ayrı ayrı okunan mantıksal bileşenleri ayrı tutun (örneğin, grupları daha sonra yineleyebilmek istiyorsanız, sohbet odaları için mesajları, odalar hakkındaki meta bilgileri ve üye listelerini aynı yere koymayın).

Firebase'in gerçek zamanlı verileri ile bir SQL ortamı arasındaki temel fark, verileri sorgulamaktır. Verinin gerçek zamanlı doğası nedeniyle "X = Y OLDUĞUNDA KULLANICILARI SEÇİN" demenin basit bir yolu yoktur (sürekli olarak değişir, parçalanır, uzlaştırılır, bu da senkronize edilmiş istemcileri kontrol altında tutmak için daha basit bir dahili model gerektirir)

Basit bir örnek muhtemelen sizi doğru zihin durumuna getirecektir, işte burada:

/users/uid
/users/uid/email
/users/uid/messages
/users/uid/widgets

Şimdi, hiyerarşik bir yapıda olduğumuz için, kullanıcıların e-posta adreslerini yinelemek istersem, şöyle bir şey yapıyorum:

// I could also use on('child_added') here to great success
// but this is simpler for an example
firebaseRef.child('users').once('value')
.then(userPathSnapshot => {
   userPathSnapshot.forEach(
      userSnap => console.log('email', userSnap.val().email)
   );
})
.catch(e => console.error(e));

Bu yaklaşımdaki sorun sadece kullanıcılara tümünü indirmeyi müşteri zorladı olmasıdır messagesve widgetsçok. Bunların hiçbiri binlerce değilse bile önemli değil. Ancak, her biri 5.000'den fazla mesaj içeren 10.000 kullanıcı için büyük bir sorun.

Şimdi hiyerarşik, gerçek zamanlı bir yapı için en uygun strateji daha açık hale geliyor:

/user_meta/uid/email
/messages/uid/...
/widgets/uid/...

Bu ortamda son derece yararlı olan ek bir araç endekslerdir. Belirli özniteliklere sahip bir kullanıcı dizini oluşturarak, dizini yineleyerek bir SQL sorgusunu hızlı bir şekilde simüle edebilirim:

/users_with_gmail_accounts/uid/email

Şimdi, diyelim ki gmail kullanıcıları için mesajlar almak istersem, bunun gibi bir şey yapabilirim:

var ref = firebase.database().ref('users_with_gmail_accounts');
ref.once('value').then(idx_snap => {
   idx_snap.forEach(idx_entry => {
       let msg = idx_entry.name() + ' has a new message!';
       firebase.database().ref('messages').child(idx_entry.name())
          .on(
             'child_added', 
             ss => console.log(msg, ss.key);
          );
   });
})
.catch(e => console.error(e));

Başka bir SO gönderisinde verileri denormalize etme hakkında bazı ayrıntılar sundum, bu yüzden bunları da kontrol edin . Frank'in Anant'ın makalesini zaten yayınladığını görüyorum, bu yüzden burada tekrar etmeyeceğim, ama aynı zamanda harika bir okuma.


Bu görüş için teşekkürler Kato!
hopper

2
Şu an için. Firebase'in v2 sürümündeki görünümler, bu süreci otomatikleştirmek için bazı harika yetenekler içerecek.
Kato

Burada eski bir yorum dizisini yeniden canlandırdığımın farkındayım, ancak daha güncel bir çözüm bulmakta zorlanıyorum. Hala en iyi yaklaşım bu mu? yani tüm users_with_gmail_accounts alınıyor ve sonra forEach çalıştırılıyor mu?
owiewio

48

Firebase, ilişkisel bir veritabanı gibi değildir . Herhangi bir şeyle karşılaştırmak isterseniz, hiyerarşik bir veritabanıyla karşılaştırırım.

Anant, kısa bir süre önce Firebase blogunda verilerinizi normalden farklılaştırma hakkında harika bir gönderi yazdı: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

Her başvuru sahibinin çocuğu olarak her başvurunun "kimliğini" saklamayı gerçekten öneririm.


Teşekkürler Frank! Bu gerçekten faydalıdır. Tam olarak aradığım şey!
hopper

4

Senaryonuz ilişkisel dünyada birden çoğa benziyor, örneğinize göre bir başvuru sahibinin birçok başvurusu var. Firebase nosql yoluna gelirsek aşağıdaki gibi görünüyor. Herhangi bir performans sorunu olmadan ölçeklenmelidir. Bu nedenle aşağıda belirtildiği gibi normalleştirmeye ihtiyacımız var.

applicants:{
applicant1:{
    .
    .
    applications:{
        application1:true,
        application3:true
    }
},
applicant2:{
    .
    .
    applications:{
        application2:true,
        application4:true
    }
}}

applications:{
application1:{
    .
    .
},
application2:{
    .
    .
},
application3:{
    .
    .
},
application4:{
    .
    .
}}

Güzel ama bir takipçim var, bu yapıyı Swift'den veya Firebase SDK kullanarak herhangi bir yerden nasıl oluşturabiliriz? Ayrıca, uygulamalar düğümüne eklenen yeni verilerin, Firebase doğrulama kurallarını kullanarak uygulamalar listesinde gerçekten var olduğunu nasıl doğrulayabiliriz?
Tommie C.

@prateep, Güzel örnek. Ancak burada sorun, application1'in bazı başvuru sahipleri için çocuk olduğu yol uygulamalarını / application1'i sildiğimde. Başvuranlara / başvuruya1 erişmeye çalışırsam, orada olmayan. bu nedenle, başvuru1: {başvuru sahipleri: {başvuru sahipleri: {başvuru1: doğru} ...} gibi her iki yerde de dizinleri güncellemeniz gerekiyor, bu yüzden şimdi başvuru1'i sildiğimde alt başvuru sahiplerini kontrol etmem ve başvuru için başvuru sahiplerinin çocuk düğümünü güncellemem gerekiyor. :)
Satish Sojitra
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.