1. ホーム
  2. firebase

[解決済み] firebaseでデータを構造化するのに最適な方法は?

2022-09-08 17:18:21

質問

firebaseを初めて使うのですが、データを構造化するのに最適な方法を教えてください。

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

私のプロジェクトには、申請者と申請書があります。1人の申請者は複数のアプリケーションを持つことができます。この2つのオブジェクトをFirebase上でどのように関連付けることができますか?リレーショナルデータベースのように動作するのでしょうか?それとも、データ設計の面で全く異なるアプローチが必要でしょうか?

どのように解決するのですか?

アップデイト : 現在では doc が追加されました。 . また、この素晴らしい投稿を参照してください。 NoSQL データ構造 .

RDBMS とは対照的に、階層的なデータの主な問題は、データを入れ子にできるため、誘惑に駆られることです。一般に、結合文やクエリーがないにもかかわらず、データをある程度正規化したいものです (ちょうど SQL で行うように)。

また 非正規化 を非正規化する必要があります。これはすべての大規模なアプリ (たとえば Twitter や Facebook) で使用されている手法であり、DRY 原則には反しますが、一般にスケーラブルなアプリに必要な機能です。

ここでの要点は、読み取りを簡単にするために書き込みに力を入れたいということです。別々に読み込まれる論理的なコンポーネントは別々にします (たとえば、チャット ルームでは、メッセージ、ルームに関するメタ情報、およびメンバーのリストをすべて同じ場所に配置しないでください。)

FirebaseのリアルタイムデータとSQL環境の主な違いは、データのクエリです。データのリアルタイムの性質のために、"SELECT USERS WHERE 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 もあります。どれも何千という数でなければ大したことはありません。しかし、それぞれ 5k 以上のメッセージを持つ 10k 人のユーザーにとっては大きな問題です。

これで、階層的なリアルタイム構造に対する最適な戦略がより明らかになりました。

/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の記事でいくつかの詳細を提供しました。 を作成しましたので、そちらもご覧ください。 . FrankがAnantの記事を既に投稿しているようなので、ここでは繰り返しませんが、こちらも素晴らしい読み物です。