我正在构建一个应用程序,用户可以在其中发布猫的图片,而其他用户可能会“喜欢”这些图片。
我需要能够查询最喜欢的图片,以及查询特定用户喜欢的图片。
我正在尝试决定如何为“喜欢”数据建模。特别是,有以下选项:
将喜欢的照片存储在猫照片文档中作为地图。喜欢:
//cats:
{
likes: {
[userId: string]: {
user: {
id: string,
displayName: string,
profilePhoto: string
},
createTime: Date
}
},
nLikes: number
}
将喜欢的照片以数组的形式存储在猫照片文档中,将用户数据存储为未索引的地图,例如:
//cats
{
...
likeIds: string[], // userIds
likeUsers: { // <- unindexed
[userId: string]: ...
}
}
创建一个具有/likes
引用的新顶级集合catId
。
我认为,因为我最经常想获得一张特定图片的所有赞(并显示喜欢图片的人的用户名和个人资料照片),因此使用地图(选项1)很有意义。因为我可以说类似这样的话,这也使我的查询更简单:
db.collection('cats').where(`likes.${userId}.user.id`, '==', userId)
获取给定用户喜欢的所有cat文档。
另一方面,在阅读了这些limitations on indexes之后,我担心上面的userId
映射将如何与索引交互。由于在我的收藏夹中的所有文档中,都会出现许多不同的userId
条目(实际上,如果我的猫图片共享站点成功,那么条目数百万个)。因为我假设为集合中任何文档中的每个唯一键值都创建了一个索引,所以它看起来很快就会超出索引限制。
选项2允许使用array-contains
查询来查找某些用户喜欢的猫。但是,我不知道数组和映射与索引交互的方式是否不同。在Firestore内部,将数组转换为{[userId: string]: true}
映射的可能性似乎很高,在索引编制方面,与选项1相同。
最后,使用选项3(顶级/likes
集合)绝对可以保证索引大小,并允许我以清晰的方式查询内容。但是,这似乎违背了Firestore的理念,即对数据进行非规范化以优化读取。对于我最受欢迎的猫咪图片(每天可能有成千上万的用户喜欢并且每天有成千上万的人观看),我现在需要进行多次读取才能检索喜欢该照片的人的用户信息,并进行成本核算$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$预防故障全部故障停机掉就使应用停机了。
因此,总而言之,我对选项1和2中不良索引交互的担忧是否合法?如果userId(在集合中的所有文档中)的数量变大,它们是否将那些作为可行的策略消除?即使读取次数/使用该应用程序的成本增加了,在这种情况下我还是会被迫进入选项3?
谢谢!