我有一个拥有数百万数据的数据库。这些数据包含名称但我有两种类型的名称
具有给定名称的数据(denomination
键)
或
具有人名的数据(firstName
和lastName
键,我没有在数据中连接两者的键)
我想创建一个API,搜索给定名称和人名的查询
为此,我必须在denomination
键和连接的firstName
lastName
键上搜索查询
这就是为什么我首先将firstName
和lastName
键连接到identity
键。
然后我想做一个聚合来匹配我对这两个键的查询
aggregate([
{$addFields:{'identite':{$concat:["$lastName",' ',"$firstName"]}}},
{
$match:{
$and:[{
$or : [
{
'denomination':toUpper(MySearchQuery])
},
{
'identite':toUpper(MySearchQuery)
}
]
}
/*Here, i'll be able to add more conditions*/
]
}
}
])
我的问题是在这种情况下如何管理索引?我是否必须索引我的连接键(identity
,但它不存在于我的数据)和denomination
。或者我必须索引firstName
,lastName
和denomination
如果你有更好的解决方案来做我的搜索,我也接受
提前感谢。
在您的示例中,只有第一个$match
阶段将使用.aggregation
查询中的索引进行改进。在这种情况下,您需要修改查询:
.aggregate([
{
$match: {
firstName: "John",
lastName: "Doe",
}
},
...
])
并为您的集合创建一个复合索引,如:{ firstName: 1, lastName: 1 }
你可能想检查这篇文章,特别是管道操作符和索引部分从MongoDB文档。
更新根据你的问题:
问题是我将无法分离firstName和lastName。它就像一个搜索栏,你可以在同一个查询中输入firstName和lastName。这就是为什么我要把它们连接起来
有多种方法可以实现它。最好的方法是使用$text索引和文本搜索。我每天在一个有100多万个文档的生产数据库上使用它。
Mongoose文本索引示例:
YourSchema.index(
{
'firstName': 'text',
'lastName': 'text',
},
{
weights:
{
'firstName': 2,
'lastName': 1
},
name: 'SearchQuery',
})
这是一个用于在多个字段中搜索的文本索引的示例。但是,如果您想寻找Joe Doe
作为firstName & lastName
的组合,您也可以使用虚拟字段(不确定100%)或为文本索引添加单独的字段,如:
收集模式
{
firstName: string,
lastName: string,
// ++combinedName: string
}
,然后为combinedName
字段添加单独的文本索引。
v2更新
不幸的是,您不能在您的情况下使用猫鼬虚拟,最好的方法是创建另一个与firstLastName
相结合的字段,并添加一个具有适当权重的$text查询索引(实际上支持语言和大小写敏感搜索)到denomination
和firstLastName
字段,如我上面所述。
另一个相关的,但不是MongoDB的选项是在ElasticSearch中存储部分集合。
是避免用户搜索查询(反应时间很敏感,不应该超过2s)的性能问题的唯一方法,并且不需要重新构建整个模式。
你也可以让它成为可能,如果你使用mongoose驱动的mongo,与default
属性,在那里你可以从this.lastName
和this.lastName
预定义你的firstLastName
值,所以你不需要每次手动添加它。
但是,当然,第一次,您需要通过游标更新整个连接:
await YourModel
.find()
.cursor()
//.sort(by proprery not sure)
.eachAsync(async (doc) => {
doc.firstLastName = `${doc.firstName} ${doc.lastName}`;
await doc.save();
})
或updateMany
(但updateMany是长查询,不像游标那么好控制)