如果我有一个简单的集合,例如:
Fruits:
Banana:
title: "Banana"
vitamins: ["potassium","B6","C"]
Apple:
title: "Apple"
vitamins: ["A","B6","C"]
如果我想搜索含有维生素B6的水果,我会做以下事情:
db.collection("Fruits").whereField("vitamins", arrayContains: "A").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
这样我就可以看到我收藏的所有含有维生素A的水果了。然而,我如何能够搜索含有多种维生素的水果,比如维生素B6和C?我不能简单地搜索["B6","C"]
,因为它将寻找一个数组,而不是独立的字符串。
这在云之火中是可能的吗?如果没有,是否有其他替代方法?
6条答案
按热度按时间4c8rllxm1#
通过在查询中链接条件,可以很容易地查找匹配多个条件的文档:
但是关于复合查询的文档建议,当前不能在单个查询中包含多个arrayContains条件。
所以,这是不可能的与你今天所拥有的。考虑使用map结构而不是数组:
然后你可以这样查询:
kd3sttzy2#
Firestore在2019年底引入了whereIn、arrayContains和arrayContainsAny方法。这些方法执行逻辑“或”查询,但您可以传入的子句限制为10个(因此您最多可以搜索10种维生素)。
一些解决方案已经提到了重组数据。利用重组方法的另一个解决方案是不将Vitamins包括到Fruit文档中,而是相反。这样你就得到了所有的文件'香蕉'的一部分。
此解决方案允许您规避10个子句的限制。它在一次读取操作中获取所有在其“Fruits”数组中包含“Banana”的“Vitamin”文档(如果太多,请考虑分页)。
gcmastyq3#
在Firestore中无法执行多个数组包含查询。但是,您可以合并尽可能多的
where
条件。因此,请考虑以下情况:但是,这仍然不允许一个干净的
OR
搜索。要查询含有维生素x或维生素y的水果,你必须更有创造力。此外,如果有很多可能的值,并且它们需要与复合查询组合,则不应使用此方法。这是因为Firestore不允许超过200个综合指数,每个综合指数都需要指定确切的维生素。这意味着您必须为vitamins.b6
、vitamins.potassium
等创建单独的复合索引。而你总共只有200美元js5cn81o4#
在Firestore中无法查询包含多个
arrayContains
的Firestore数据库。如果您使用多个,则可能会出现以下错误:无效查询。查询仅支持具有单个数组包含筛选器。
如果需要过滤多个维生素,则需要更改数据库的结构逻辑,方法是为每个维生素创建属性,然后链接
.whereField()
函数调用。我知道这听起来有点奇怪,但这就是Cloud Firestore的工作原理。你的schema应该是这样的:
要查找含有
potassium
、B6
和C
维生素的所有水果,您应该使用如下所示的查询:dxxyhpgq5#
它已经被评论过了,但是如果你的查询要求你创建一个复合索引,那么这个被接受的答案是不可行的,因为它可能会导致你的复合索引计数很快达到200的限制。这是一个很麻烦的方法,但我能想到的最好的解决方案是以某种有保证的顺序存储,例如。按字母顺序-给定水果的维生素的每个组合的数组,每个组合被连接为字符串。例如,由于香蕉含有B6,C和钾,香蕉的一系列维生素组合将是:
B6
B6||C
B6||C||potassium
B6||potassium
C
C||potassium
potassium
然后,如果你的用户正在搜索每一种同时含有B6和钾的水果,你的查询将是:
1aaf6o9v6#
我想我找到了一种很好的方法,避免了为map值创建所有索引
如果你create all array combinations possible from an array of values
您可以排序并使用逗号或其他分隔符将它们连接起来
,然后存储字符串数组(必须排序),并使用排序的分隔搜索查询执行
array-contains
。好奇我是不是漏掉了什么