要回答这个问题,你需要“计算”满足条件的匹配数,以便将结果“排序”并优先返回最多匹配项的结果。
为此,你需要使用聚合框架,在 MongoDB 中用于数据的“计算”和“操作”:
db.multiArr.aggregate([
{ "$match": { "Keys": { "$in": [ "carrot", "banana" ] } } },
{ "$project": {
"ID": 1,
"Keys": 1,
"order": {
"$size": {
"$setIntersection": [ ["carrot", "banana"], "$Keys" ]
}
}
}},
{ "$sort": { "order": -1 } }
])
如果您使用的是 MongoDB 3 版本以下的较旧版本,则可以使用长格式:
db.multiArr.aggregate([
{ "$match": { "Keys": { "$in": [ "carrot", "banana" ] } } },
{ "$unwind": "$Keys" },
{ "$group": {
"_id": "$_id",
"ID": { "$first": "$ID" },
"Keys": { "$push": "$Keys" },
"order": {
"$sum": {
{ "$cond": [
{ "$or": [
{ "$eq": [ "$Keys", "carrot" ] },
{ "$eq": [ "$Keys", "banana" ] }
]},
1,
0
]}
}
}
}},
{ "$sort": { "order": -1 } }
])
无论哪种情况,该函数的功能首先是通过提供一个带有
$in
的“列表”参数来匹配可能的文档与条件。一旦获取了结果,您就想要在数组中“计数”匹配元素的数量,以与提供的“列表”可能值进行匹配。
现代形式中,
$setIntersection
运算符比较两个“列表”,返回仅包含“唯一”匹配成员的新数组。由于我们想知道有多少匹配项,因此只需返回该列表的
$size
即可。
在旧版本中,您需要使用
$unwind
拆分文档数组,以便对其执行操作,因为旧版本缺乏可在不改变数组的情况下使用的新运算符。然后该过程逐个查看每个值,如果
$or
表达式中的任一表达式与可能的值相匹配,则
$cond
三元运算符将返回
1
的值,以便累加器
$sum
,否则返回
0
。净结果与现代版本所示的“匹配计数”相同。
最后一件事就是根据返回的“匹配计数”
$sort
结果,让最多的匹配在“顶部”。这是“降序”,因此您提供
-1
来指示。
关于$in和数组的补充说明
首先,您对MongoDB查询有一些误解。实际上,$in
运算符是为像这样的“列表”参数而设计的:
{ "Keys": { "$in": [ "carrot", "banana" ] } }
这本质上是说:“在‘Keys’属性中匹配‘carrot’或‘banana’”,这相当于一种简写方式。
。甚至可以这样长形式书写:
“在‘Keys’属性中匹配‘carrot’或‘banana’”。
{ "$or": [{ "Keys": "carrot" }, { "Keys": "banana" }] }
如果它是一个"单个"匹配条件,那么你只需要提供要匹配的值到属性中:
{ "Keys": "carrot" }
因此,这应该涵盖了一个误解,即您使用$in
来匹配文档内的数组属性。相反,"反向"情况是预期用法,您将提供"参数列表"来匹配给定属性,无论该属性是数组还是单个值。
MongoDB查询引擎在等式或类似操作中不区分单个值或值数组。