您当前的数据 struct 非常适合查找特定聊天的参与者.然而,对于查找相反的内容:用户参与的聊天,它不是一个很好的 struct .
这里有几个问题:
- 您将set存储为一个数组
- 只能在固定路径上建立索引
Set vs array
一个聊天可以有多个参与者,所以您将其建模为一个array.但这实际上并不是理想的数据 struct .很可能每个参与者只能参与一次聊天.但通过使用数组,我可以:
participants: ["puf", "puf"]
这显然不是您想要的,但是数据 struct 允许这样做.您可以try 在代码和安全规则中保护这一点,但是如果您从隐式地更好地匹配您的模型的数据 struct 开始会更容易.
我的经验法则是:if you find yourself writing 100, you should be using a set.
集合是一种 struct ,每个子元素最多只能出现一次,因此它自然可以防止重复.在Firebase中,您可以将集合建模为:
participants: {
"puf": true
}
这里的true
实际上只是一个虚拟值:重要的是我们已经将名称移到了键上.现在,如果我再试着加入这个聊天,那我就不会同意了:
participants: {
"puf": true
}
当你加入时:
participants: {
"john": true,
"puf": true
}
这是对您的需求最直接的表示:一个只能包含每个参与者一次的集合.
You can only index known properties
使用上面的 struct ,您可以could查询与您在一起的聊天内容:
ref.child("chats").orderByChild("participants/john").equalTo(true)
问题是,这需要在"参与者/约翰"上定义一个索引:
{
"rules": {
"chats": {
"$chatid": {
"participants": {
".indexOn": ["john", "puf"]
}
}
}
}
}
这将起作用,表现出色.但现在每次有新用户加入聊天应用程序时,你都需要添加另一个索引.这显然不是一个可伸缩的模型.我们需要更改数据 struct 以允许您进行所需的查询.
Invert the index - pull categories up, flattening the tree
第二条经验法则:model your data to reflect what you show in your app.
由于您希望为用户显示聊天室列表,请存储每个用户的聊天室:
userChatrooms: {
john: {
chatRoom1: true,
chatRoom2: true
},
puf: {
chatRoom1: true,
chatRoom3: true
}
}
现在,您只需通过以下方式确定聊天室列表:
ref.child("userChatrooms").child("john")
然后把 keys 循环到每个房间.
您的应用程序中会有两个相关列表:
在这种情况下,您还会在数据库中同时拥有这两个列表.
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
这是Cloud Firestore更好地支持此类查询的情况之一.它的array-contains
运算符允许过滤数组中具有特定值的文档,而arrayRemove
运算符允许将数组视为一个集合.更多信息,请参见Better Arrays in Cloud Firestore.