我在如何最好地构建我的(非常简单的)Firestore应用程序时遇到了一些麻烦。我有一组像这样的用户:
users: {
'A123': {
'name':'Adam'
},
'B234': {
'name':'Bella'
},
'C345': {
'name':'Charlie'
}
}
...并且每个用户都可以像'或者不喜欢'任意数量的其他用户(如Tinder)。
我想构建一个"喜欢"桌子(或等同的Firestore),以便我可以列出我尚未喜欢或不喜欢的人。我最初的想法是创造一个"喜欢" user表中的对象,其布尔值如下:
users: {
'A123': {
'name':'Adam',
'likedBy': {
'B234':true,
},
'disLikedBy': {
'C345':true
}
},
'B234': {
'name':'Bella'
},
'C345': {
'name':'Charlie'
}
}
如果我是查理并且我知道我的身份证,那么我可以列出我尚未喜欢或不喜欢的用户:
var usersRef = firebase.firestore().collection('users')
.where('likedBy.C345','==',false)
.where('dislikedBy.C345','==',false)
这不起作用(每个人都被列出)所以我怀疑我的方法是错误的,特别是' == false'部分。有人可以指出我如何构建这个的正确方向?作为一个额外的额外问题,如果有人改名,会发生什么?我是否需要更改所有嵌入式" likesBy"数据?或者我可以使用云功能来实现这一目标吗?
谢谢!
答案 0 :(得分:3)
此问题没有完美的解决方案,但根据您想要的权衡取舍,您可以做其他选择。
请记住,Cloud Firestore仅允许根据数据集总大小进行扩展的查询。
这对于防止您构建在10个文档的测试中起作用的东西非常有用,但是一旦您开始制作并变得流行,它就会爆炸。不幸的是,这类问题并不适合这种可扩展模式,而且您拥有的配置文件越多,人们创建的内容越多,回答您想要的查询所需的时间就越长。
然后,解决方案是找到一个或多个可扩展且最接近代表您想要的查询。我可以想到两种选择,以不同的方式进行权衡:
在Overscan选项中,您基本上交易增加的成本以获得100%的准确性。
考虑到你的用例,我想这可能是你最好的选择。由于配置文件的总数可能比个人喜欢的配置文件数量大几个数量级,因此过度扫描的成本增加可能是无关紧要的。
只需选择与您拥有的任何其他条件匹配的所有个人资料,然后在客户端,过滤掉用户已经喜欢的任何内容。
首先,获取用户喜欢的所有个人资料:
var likedUsers = firebase.firestore().collection('users')
.where('likedBy.C345','==',false)
然后获取所有用户,检查第一个列表并丢弃任何匹配的内容。
var allUsers = firebase.firestore().collection('users').get()
根据比例,您可能希望优化第一步,例如每当用户喜欢某人时,为他们喜欢的每个人更新该用户的单个文档中的数组。这样,您只需为第一步获取单个文档。
var likedUsers = firebase.firestore().collection('likedUsers')
.doc('C345').get()
由于此查询确实按结果集的大小进行扩展(通过将结果集定义为数据集),因此Cloud Firestore可以在没有一堆隐藏的不可扩展工作的情况下回答它。不可扩展的部分留待您优化(上面有两个例子)。
在Underscan选项中,您基本上可以交易准确性以获得更窄(因此更便宜)的结果。
这种方法比较复杂,所以你可能只想考虑它,如果出于某种原因,我喜欢Overscan选项中不喜欢不喜欢的比例。
如果您确实喜欢他们,那么基本的想法是排除他人,并接受权衡,即您可能也会排除您尚未喜欢的人 - 是的,基本上是Bloom filter
在每个用户个人资料商店中,true
/ false
值的地图从0
到m
(我们将m
转到false
稍后),最初将所有内容都设置为true
。
当用户喜欢该个人资料时,计算要插入到布隆过滤器中的用户ID的哈希值,并将地图中的所有这些位设置为C345
。
如果我们使用m = 4
,让我们说likedBy: {
0: false,
1: true,
2: true,
3: false }
哈希到0110,那么你的地图就像:
0
现在,要找到您绝对不喜欢的人,您需要使用相同的概念对地图中的每个位进行查询。对于您的哈希为真的任何位m
到var usersRef = firebase.firestore().collection('users')
.where('likedBy.1','==',false)
,请查询它为假:
false
等。 (当我们将来支持OR查询时,这将变得更容易)。任何对用户的ID哈希值为true
的位置具有m = 1675
值的人肯定不会被他们所喜欢。
由于您不太可能想要显示所有配置文件,只需要显示单个页面,您可以随机选择一个ID为正确的哈希位并仅查询它。如果您的配置文件用完了,只需选择另一个真实并重新启动。
假设大多数个人资料被喜欢500次或更少次,您可以使用m
将误报率保持在20%或更低。
有一些方便的在线计算器可帮助您计算每个配置文件的喜欢比例,所需的误报率以及m
,for example here。
您会在Overscan选项中快速意识到,每次运行查询时,都会显示用户上次不喜欢的相同配置文件。我假设你不想要那个。更糟糕的是,用户喜欢的所有内容都会在查询的早期,这意味着您最终不得不一直跳过它们并增加成本。
有一个简单的解决方法,使用我在这个问题上描述的方法,Firestore: How to get random documents in a collection。这将使您能够从集合中提取随机配置文件,从而为您提供更均匀的分布,并减少在许多以前喜欢的配置文件上遇到障碍的可能性。
我怀疑你在Underscan选项中遇到的一个问题是非常受欢迎的个人资料。如果某人几乎总是被人喜欢,那么如果该个人资料的大小不合理以保留在单个文档中,您可能会开始超出布隆过滤器的用途(您希望8000
小于说x%
1}}以避免在Cloud Firestore中遇到每个文档索引限制。
对于此问题,您希望仅为这些配置文件组合Overscan选项。使用云函数,任何超过popular
映射设置为true的配置文件都会将{{1}}标志设置为true。在流行的旗帜上过度扫视所有人并将它们编织到你的Underscan结果中(记得做丢弃设置)。