テーブルの構造は次のとおりです。
等
私がやろうとしているのは、チャットテーブルをクエリして、渡されたユーザー名文字列で参加者を保持しているすべてのチャットを見つけることです。
ここに私がこれまでに持っているものがあります:
subscribeChats(username: string) {
return this.af.database.list('chats', {
query: {
orderByChild: 'participants',
equalTo: username, // How to check if participants contain username
}
});
}
現在のデータ構造は、特定のチャットの参加者を検索するのに最適です。ただし、逆を検索するにはあまり良い構造ではありません。ユーザーが参加しているチャットです。
ここにいくつかの問題:
チャットには複数の参加者がいる可能性があるため、これを配列としてモデル化しました。しかし、これは実際には理想的なデータ構造ではありません。おそらく、各参加者は一度だけチャットに参加できます。しかし、配列を使用することで、次のことが可能になります。
_participants: ["puf", "puf"]
_
それは明らかにあなたが念頭に置いているものではありませんが、データ構造はそれを可能にします。コードとセキュリティルールでこれをセキュリティで保護することはできますが、暗黙的にモデルによく一致するデータ構造から始める方が簡単です。
私の経験則:array.contains()
を書いていることに気付いたら、setを使用する必要があります。
セットは、各子が1回しか存在できない構造であるため、重複から自然に保護されます。 Firebaseでは、セットを次のようにモデル化します。
_participants: {
"puf": true
}
_
ここのtrue
は実際には単なるダミー値です。重要なことは、名前をキーに移動したことです。もう一度このチャットに参加しようとすると、何もしません。
_participants: {
"puf": true
}
_
そして、あなたが参加するとき:
_participants: {
"john": true,
"puf": true
}
_
これは、要件を最も直接的に表現したものです。各参加者を1回しか含めることができないコレクションです。
上記の構造では、あなたがいるチャットをcouldクエリできます:
_ref.child("chats").orderByChild("participants/john").equalTo(true)
_
問題は、「participants/john」でインデックスを定義するよりもこれが必要なことです。
_{
"rules": {
"chats": {
"$chatid": {
"participants": {
".indexOn": ["john", "puf"]
}
}
}
}
}
_
これはうまく機能し、うまく機能します。ただし、チャットアプリに新しい誰かが参加するたびに、別のインデックスを追加する必要があります。これは明らかにスケーラブルなモデルではありません。必要なクエリを許可するには、データ構造を変更する必要があります。
2番目の経験則:データをモデル化し、アプリに表示する内容を反映します。
ユーザーのチャットルームのリストを表示するため、各ユーザーのチャットルームを保存します。
_userChatrooms: {
john: {
chatRoom1: true,
chatRoom2: true
},
puf: {
chatRoom1: true,
chatRoom3: true
}
}
_
これで、チャットルームのリストを次のように簡単に決定できます。
_ref.child("userChatrooms").child("john")
_
次に、キーをループして各部屋を取得します。
アプリには2つの関連リストがあります。
その場合、データベースにも両方のリストがあります。
_chatroomUsers
chatroom1
user1: true
user2: true
chatroom2
user1: true
user3: true
userChatrooms
user1:
chatroom1: true
chatroom2: true
user2:
chatroom1: true
user2:
chatroom2: true
_
Firebaseはデータのネストを推奨していないため、両方のリストをツリーの最上位にプルしました。
NoSQLソリューションでは、両方のリストを作成することは完全に正常です。上記の例では、userChatrooms
をchatroomsUsers
の逆インデックスとして参照します。
これは、Cloud Firestoreがこのタイプのクエリをより適切にサポートするケースの1つです。 _array-contains
_演算子を使用すると、配列内の特定の値を持つドキュメントをフィルター処理できますが、arrayRemove
を使用すると、配列をセットとして扱うことができます。詳細については、「 Cloud Firestoreのより良い配列 」を参照してください。