的幾個問題在這裏:
Set vs array
一個聊天可以有多個參與者,所以你將它建模爲一個數組。但這實際上並不是理想的數據結構。可能每個參與者只能進行一次聊天。但通過使用陣列,我可以有:
participants: ["puf", "puf"]
這顯然不是你想到的,但數據結構允許它。你可以嘗試在代碼和安全規則中保證這一點,但如果你從一個更好地隱含地匹配你的模型的數據結構開始,它會更容易。
我的經驗法則:如果你發現自己寫作array.contains()
,你應該使用一套。
一組是每個孩子最多可以出現一次的結構,所以它自然可以防止重複。
participants: {
"puf": true
}
這裏的true
真的只是虛值:在火力地堡你會成爲一系列的模型,重要的是我們搬到名稱的關鍵。現在,如果我嘗試重新加入該聊天,這將是一個空操作:
participants: {
"puf": true
}
而當你想加入:
participants: {
"john": true,
"puf": true
}
這是你的要求,最直接的表現:一隻能包含每個參與者一次的集合。
只能索引固定的路徑
通過上述結構,你可以查詢聊天記錄,你是在用:
ref.child("chats").orderByChild("participants/john").equalTo(true)
的問題是,這需要比您定義的索引關於`參與者/約翰':
{
"rules": {
"chats": {
"$chatid": {
"participants": {
".indexOn": ["john", "puf"]
}
}
}
}
}
這將工作和表現很好但現在每次有人新加入聊天應用程序,我需要添加另一個索引。這顯然不是一個可擴展的模型。我們需要改變我們的數據結構以允許你想要的查詢。
反轉指標 - 拉類別了,壓扁了的樹大拇指的
第二條規則:模型數據以反映您在您的應用程序顯示的內容。
既然你正在尋找展示的聊天室列表爲用戶,存儲聊天室爲每個用戶:
userChatrooms: {
john: {
chatRoom1: true,
chatRoom2: true
},
puf: {
chatRoom1: true,
chatRoom3: true
}
}
現在,你可以簡單地確定你與聊天室列表:
ref.child("userChatrooms").child("john")
然後循環按鍵來獲得每個房間。
你會喜歡有兩個相關的列出你的應用程序:
- 的聊天室爲特定用戶
- 參與者在一個特定的聊天室列表中的列表
在這種情況下,你也將在數據庫中同時有兩個列表。
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
。
這是一個很棒的解釋。我有我的數據存儲這樣,這使我可以從用戶的列表抓住聊天室,或從聊天室的成員抓住用戶。但它不允許觀察'.childChanged'作爲我所屬的聊天室。如果我嘗試爲'members/myId = true'設置聊天觀察者,那麼我得到未指定的索引錯誤。你會怎麼做呢?我有一個問題發佈在這裏: https://stackoverflow.com/questions/47769044/swift-firebase-using-an-unspecified-index –
@ frank-van-puffelen引用你最後的代碼片段,讓我們說我是「user1 「並且我取得了我所屬的聊天室的所有鑰匙。然後爲每個聊天室密鑰獲取完整的聊天室對象,並在列表中顯示聊天室列表。不過,如果我還需要訪問作爲聊天室一部分的完整用戶對象,那很好。看起來很奇怪,我必須爲每個單個聊天室中的每個單個用戶獲取另一個for循環(2級嵌套for循環!)來獲取該數據。有沒有更好的辦法? – damirstuhec