这是我在尝试将地理位置与Firestore混合使用时遇到的一个问题。长话短说-我需要在用户所在位置附近的餐馆。为了完成地理搜索,我使用了Algolia。当我向Algolia发送请求时,它会返回一个数组的唯一餐厅ID,这些ID与Firestore文档ID相对应。这样就可以了。
使事情变得复杂的是,我还需要两个条件-我需要将查询限制为平均评分> = 8的餐馆。而且我还想限制返回文档的数量(2、5、20等) 。
这就是伪代码中的样子:
db.restaurantsCollection
.documentIds([111, 222, 333, 444, 555, 666, 777, 888, 999])
.whereField("averageRating", isGreaterThanOrEqualTo: 8)
.order(by: "averageRating", descending: true)
.limit(to: 2)
.getDocuments()
到目前为止,我知道Firestore不支持具有多个文档ID的查询。那么执行这种查询的最优化方法是什么?
如果我在文档中将documentId
设置为id
字段,然后遍历从Algolia返回的所有ID,然后执行类似的操作(那么我可以纯粹地进行排序和限制Swift):
for id in ids {
db.restaurantsCollection
.whereField("averageRating", isGreaterThanOrEqualTo: 8)
.whereField("id", isEqualTo: id)
.getDocuments()
}
但这仍然意味着很多请求。还有其他想法吗?
答案 0 :(得分:0)
如果这对我发布的任何人有帮助,那么如果您以我实现它们的方式实现地理查询,可以考虑使用Algolia。因此,使用Algolia的方式是保持搜索索引的坐标。
例如:
{
"_geoloc": {
"lng": 8.507785799999999,
"lat": 47.17652589999999
},
"objectID": "1234abcd"
}
其中objectID对应于餐厅或您要进行地理查询的任何场所的文档ID。
然后,您通过Algolia API创建查询。如果要获取CLLocation周围的所有项目,则应进行设置-为此,请使用query.aroundLatLng
属性。您还可以以米为单位设置distance
属性。结果将是一个JSON,其中您的ID按照距离的顺序从最接近的位置开始排序。
到目前为止,我们已经解决了最大的问题-按地理位置查询。
现在,如果我想从我从阿尔及利亚获得的所有N个ID中获得最高评分,该怎么办?可悲的是,到目前为止,还没有可以通过多个ID查询的API。因此,这意味着如果我想获得所有分数大于等于8的餐厅,则需要读取N个Firestore文档,然后获得最高评分。远非理想。
使用Algolia数据保存餐厅的平均值。
我知道这意味着额外的联网,但这是一个不错的方法。缺点-每次在Firestore中更新餐厅平均价格时,也需要在Algolia中更新餐厅平均价格。如果像我一样使用Cloud Functions计算平均值,则也需要在Algolia中设置平均值。是的,这意味着您需要升级到付费Firebase计划,因为这是外部Cloud Functions调用。
现在您在阿尔及利亚的有效负载中拥有平均值,您可以轻松获取您所在地区的所有餐厅ID,然后按其阿尔及利亚评级客户端对数据进行排序。对ID进行排序后,即可从Firestore请求文档。
保存城市名称和国家
您可以将城市和国家/地区名称以及位置数据保存在Firestore中。这样,您可以将它们用于查询。伪Firestore查询代码:
db.restaurants.where("city" == "current_city").where("country" == "current_country").where("averageRating" >= 8).getDocuments()
但是,这种方法并不十分准确,并且通常适用于大城市。它还不会计算您附近的位置。
我希望这会有所帮助。
答案 1 :(得分:0)
这是一种更有效的方法:
firestoreDB
.collection("someCollection")
.whereField(FieldPath.documentID(), in: [
"05C0632C-601B-4D98-BD2B-3E809D0496B1", //up to 10 ids
"087686CA-6B21-4268-9E4C-CF833FCA92DE"
]).getDocuments { snap, error in
if let snap = snap {
snap.documents.forEach { print($0.data()) }
} else if let error = error {
print("Error: \(error)")
}
}
以10为批次获取它们可以进行排序(使用.order(by:)等) 它不是完美的,但看起来像是对您已有的改进。 您可以进行多个此类调用,然后将结果合并为一个,然后对它们进行排序。