web-dev-qa-db-ja.com

firebaseでデータを構造化する最良の方法は何ですか?

私はfirebaseが初めてで、その上でデータを構造化する最良の方法は何かを知りたいです。

私は簡単な例を持っています:

私のプロジェクトには応募者と応募者がいます。 1人の申請者が複数の申請を持つことができます。この2つのオブジェクトをfirebaseに関連付けるにはどうすればよいですか?リレーショナルデータベースのように機能しますか?または、アプローチはデータ設計の点で完全に異なる必要がありますか?

107
Ricardo Parro

UPDATE:現在、 構造化データに関するドキュメント があります。また、 NoSQLデータ構造 に関するこの優れた投稿を参照してください。

階層データの主な問題は、RDBMSとは対照的に、できるのでデータをネストしたいということです。一般に、結合ステートメントとクエリがないにもかかわらず、データをある程度(SQLの場合と同じように)正規化します。

また、読み取り効率が懸念される場所では denormalize を使用します。これは、すべての大規模なアプリ(TwitterやFacebookなど)で使用される手法であり、DRYの原則に反しますが、一般にスケーラブルなアプリの必要な機能です。

ここでの要点は、読み取りを簡単にするために書き込みに一生懸命取り組むことです。別々に読み取られる論理コンポーネントを保持します(たとえば、チャットルームの場合、メッセージ、ルームに関するメタ情報、メンバーのリストをすべて同じ場所に入れないでください。後でグループを反復できるようにする場合)。

FirebaseのリアルタイムデータとSQL環境の主な違いは、データのクエリです。 「リアルタイムでユーザーを選択してくださいX = Y」と言う簡単な方法はありません。これは、データのリアルタイム性(絶えず変化、シャーディング、調整などのため、同期されたクライアントをチェックするために簡単な内部モデルが必要です)

簡単な例はおそらくあなたを正しい心の状態に設定するでしょう。そこで、ここに行きます:

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

今、私たちは階層構造になっているので、ユーザーのメールアドレスを繰り返したい場合は、次のようにします。

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

このアプローチの問題は、クライアントのすべてのmessageswidgetsもダウンロードするようにクライアントに強制したことです。それらのどれも数千にならないなら、大したことはありません。しかし、1万人以上のユーザーがそれぞれ5万件以上のメッセージを送信するのは大変なことです。

そのため、階層的なリアルタイム構造の最適な戦略がより明確になります。

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

この環境で非常に役立つ追加ツールはインデックスです。特定の属性を持つユーザーのインデックスを作成することにより、インデックスを反復するだけでSQLクエリをすばやくシミュレートできます。

/users_with_gmail_accounts/uid/email

たとえば、Gmailユーザーのメッセージを取得したい場合は、次のようにします。

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

データの非正規化に関する別のSO投稿で詳細を提供しました だからそれらもチェックアウトしてください 。フランクはすでにアナントの記事を投稿しているので、ここでは繰り返して説明しませんが、素晴らしい読み物でもあります。

135
Kato

Firebaseは、リレーショナルデータベースのようなnotです。何かと比較したい場合は、階層型データベースと比較します。

Anantは最近、データの非正規化に関する素晴らしい記事をFirebaseブログに書きました: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html

実際、各申請の「ID」を各申請者の子として保持することをお勧めします。

48

あなたの例は、申請者が多くのアプリケーションを持っているので、あなたのシナリオはリレーショナルの世界では一対多のように見えます。 firebase nosqlの方法を使用すると、次のようになります。パフォーマンスの問題なしにスケーリングする必要があります。そのため、以下で説明する非正規化が必要です。

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

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