我正在尝试对 Firestore 集合按模式执行过滤。例如,在我的 Firestore 数据库中,我有一个名为
adidas
的品牌。用户将有一个搜索输入,其中输入“adi”、“adid”、“adida”或“adidas”会返回 adidas
文档。我指出了几个解决方案来做到这一点:
1.获取所有文档并进行前端过滤
var brands = db.collection("brands");
filteredBrands = brands.filter((br) => br.name.includes("pattern"));
由于 Firestore 定价,该解决方案显然不是一个选择。此外,如果文档数量较多,执行请求的时间可能会很长。
2. 使用Elasticsearch或Algolia
这可能很有趣。然而,我认为仅添加这些解决方案对模式搜索的支持有点矫枉过正,而且这很快就会变得昂贵。
3. 创建对象时自定义
searchName
字段
所以我有这个解决方案:在创建文档时,创建一个包含一系列可能的搜索模式的字段:
{
...
"name":"adidas",
"searchNames":[
"adi",
"adida",
"adidas"
],
...
}
以便可以通过以下方式访问该文档:
filteredBrands = db.collection("brands").where("searchNames", "array-contains", "pattern");
所以我有几个问题:
恕我直言,第一个解决方案绝对是不是的选择。下载整个集合来搜索客户端字段根本不切实际,而且成本也非常高。
第二个选项是最佳选项,因为它将帮助您在整个 Cloud Firestore 数据库中启用全文搜索。由您决定是否值得使用它。
您认为第三种方案的针对性和效率如何?
关于第三种解决方案,它可能有效,但它意味着即使品牌名称很长,您也需要创建一系列可能的搜索模式。正如我在您的架构中看到的,您正在添加从第三个字母开始的可能搜索模式,这意味着如果有人正在搜索
ad
,将找不到结果。该解决方案的缺点是,如果您有一个名为 Asics Tiger
的品牌,并且用户正在搜索 Tig
或 Tige
,您最终将再次没有结果。
对于在 Firestore 集合上执行模式过滤器,您还有其他想法吗?
如果您有兴趣仅从单个单词获取结果并使用品牌的起始字母作为模式,我向您推荐一个更好的解决方案,即使用如下所示的查询:
var brands = db.collection("brands");
brands.orderBy("name").startAt(searchName).endAt(searchName + "\uf8ff")
在这种情况下,像
a
或 ad
这样的搜索将非常有效。除此之外,不需要创建任何其他数组。这样文档写就会少了。
我还写过一篇文章,叫做:
这也可能有帮助。
2024 年 11 月代码
final collection = instanse.collection(kCardsName);
final res = await collection.where('title',
isGreaterThanOrEqualTo: searchString,
isLessThanOrEqualTo: "$searchString\uf8ff")
.get();