组合 MongoDB 列的未排序搜索
Posted
技术标签:
【中文标题】组合 MongoDB 列的未排序搜索【英文标题】:Unsorted search of combined MongoDB columns 【发布时间】:2021-09-09 01:55:51 【问题描述】:是否可以搜索由两列组成的虚拟列?
假设我有以下 MongoDB 集合:
db.collection =
[
book : 'The Stand', author : 'Stephen King',
book : 'The Dead Zone', author : 'Stephen King',
book : 'Hamlet', author : 'William Shakespeare',
book : 'The Tragedy of Othello', author : 'William Shakespeare',
book : 'Danse Macabre', author : 'Stephen King',
]
我想同时考虑book
和author
列进行搜索。特别是,我将有一个查询字符串,其中包含由空格分隔的多个项目,并且我希望返回其联合 book+author
列包含所有查询项目的文档,而不管它们的顺序如何。
例子:
查询:“国王”
book : 'The Stand', author : 'Stephen King',
book : 'The Dead Zone', author : 'Stephen King'
查询:“悲剧莎士比亚”
book : 'The Tragedy of Othello', author : 'William Shakespeare'
查询:“那个”
book : 'The Stand', author : 'Stephen King',
book : 'The Dead Zone', author : 'Stephen King',
book : 'The Tragedy of Othello', author : 'William Shakespeare',
在 MongoDB 中可以进行这种搜索吗?是否有任何$regex
表达式使其可行?
谢谢!
【问题讨论】:
提供可以复制和粘贴以进行测试的有效 JSON 非常宝贵。感谢您创建这些有效的 JSON 对象 - 包括源记录以及预期结果。 【参考方案1】:这是一个我认为可能会有所帮助的聚合......
db.collection.aggregate([
$project: book: 1, author: 1, "book_words": $split: [ "$book", " " ] , "author_words": $split: [ "$author", " " ] ,
$project: book:1, author: 1, "search_words": $concatArrays: [ "$book_words", "$author_words" ] ,
$match: "search_words": $all: [ "The", "King" ] ,
$project: "search_words": 0
]).pretty()
说明:
这个聚合有 4 个阶段...
-
$项目
$项目
$匹配
$项目
第一个 $project 会将字段“book”中的字符串值拆分为一个名为“book_words”的单词数组,并将字段“author”中的字符串值拆分为一个名为“author_words”的单词数组
第二个 $project 将两个新数组连接到一个名为“search_words”的数组中
$match 阶段过滤掉与搜索条件不匹配的记录
最后的 $project 阶段删除了名为“search_words”的临时数组字段
此聚合的结果文档看起来像...
"_id" : ObjectId("60d6139a9148371ae7d2b343"),
"book" : "The Stand",
"author" : "Stephen King"
"_id" : ObjectId("60d6139a9148371ae7d2b344"),
"book" : "The Dead Zone",
"author" : "Stephen King"
不区分大小写的匹配
为了提供不区分大小写的匹配,MongoDB 必须了解不区分大小写的含义。英文大小写不同于其他语言。因此,出于这个原因,我们必须添加一个索引,其排序规则将英语定义为语言,排序规则的强度为 2——这意味着英语不区分大小写。创建索引后,我们必须将排序规则作为聚合中的一个选项来引用。
创建索引
db.collection.createIndex( book: 1, author: 1 , collation: locale: 'en', strength: 2 )
这是两个字段的复合索引 - 'book' 和 'author'。注意此索引的排序选项...
使用排序规则进行聚合
现在索引以特定的排序规则存在,Mongo 现在可以计算不区分大小写的选项...
db.collection.aggregate([
$project: book: 1, author: 1, "book_words": $split: [ "$book", " " ] , "author_words": $split: [ "$author", " " ] ,
$project: book:1, author: 1, "search_words": $concatArrays: [ "$book_words", "$author_words" ] ,
$match: "search_words": $all: [ "the", "king" ] ,
$project: "search_words": 0
],
collation: locale: "en", strength: 2 ).pretty()
请注意,排序选项应用于聚合。此外,聚合 $match 阶段现在使用所有小写文本。
这是输出...
"_id" : ObjectId("60d6139a9148371ae7d2b343"),
"book" : "The Stand",
"author" : "Stephen King"
"_id" : ObjectId("60d6139a9148371ae7d2b344"),
"book" : "The Dead Zone",
"author" : "Stephen King"
小心
使用带有排序规则选项的正则表达式可能无法按预期工作,至少从索引策略的角度来看是这样。在我的示例中,我没有使用任何正则表达式 ($regex),因此它按预期工作。但同样,这是针对完全匹配,而不是部分匹配(也称为范围查询),例如“以 'ki*' 开头”
MongoDB Atlas 搜索
如果使用 MongoDB Atlas,则使用 Atlas Search 可以直接解决此问题,但省略了“the”等常用词。
【讨论】:
非常感谢!这绝对超出了我目前的知识范围。我稍后会测试它:) 是否可以使 $match 不区分大小写?也许使用 $toLower?我无法得到它:( @VíctorMartínez - 请在我的回答中查看不区分大小写选项的更新。以上是关于组合 MongoDB 列的未排序搜索的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MongoDB 中搜索动态字段并首先对最佳匹配结果进行排序
CosmosDB mongoDB API 排序和全文搜索抛出错误