为了支持不区分大小写或任何其他规范化,我们是否需要编写一个单独的字段来包含规范化版本并对其进行查询??。 例如:
db.collection("users").where("name", "==", "Dan")
db.collection("users").where("name_lowercase", "==", "dan")
简而言之,是的。
这是因为 Cloud Firestore(和 Firebase 实时数据库,在启用时)基于文档中每个属性的值indexed databases。
不是在数百个(如果不是数千个)文档中搜索匹配项,而是查询相关属性的索引以获取匹配的文档 ID。
考虑以下“数据库”及其基于文档中名称的索引:
const documents = {
"docId1": {
name: "dan"
},
"docId2": {
name: "dan"
},
"docId3": {
name: "Dan"
},
"docId4": {
name: "Dan"
}
}
const nameIndex = {
"dan": ["docId1, docId2"],
"Dan": ["docId3, docId4"]
}
不是在整个文档列表上调用 Object.entries(documents).filter(([id, data]) => data.name === "dan")
,您可以只询问索引而不是使用 nameIndex["dan"]
产生最终结果 ["docId1, docId2"]
几乎立即准备好被检索。>
继续同一个例子,调用 nameIndex["daniel"]
给出 undefined
(没有具有该名称的文档),它可以很快用于表示数据库中不存在数据)。
Firestore 引入了 composite indexes,它允许您跨多个属性(例如“姓名”和“年龄”)建立索引,因此您还可以快速有效地搜索名称为“Dan”但它们也是 42 年的文档年龄。
进一步阅读:Firebase 文档介绍了一种基于文本的搜索解决方案 here。
我会做什么:
在查询之前(可能是客户端):将查询词转换为两个或多个变体(最多 10 个变体)。比如搜索词“dan”(String)变成了["dan", "DAN", "Dan"]
的数组然后我会做一个“in”查询,我会在同一个 name
字段中搜索所有这些变体。
“in”查询类型最多支持 10 个带有逻辑“OR”运算符的相等 (==) 子句。 (documentation here)
这样一来,您就可以只保留一个字段“name
”并对其进行可能的变体查询。
它看起来像这样:
let query_variations = ["dan", "DAN", "Dan"]; // TODO: write a function that converts the query string into this kind of Array
let search = await db.collection("users").where("name", "in", query_variations).get();