任何“比较”或“选择”,实际上是施加的实际逻辑或多或少主观。但作为一般原则,您始终可以考虑阵列中匹配索引的乘积以及文档中存在的数组。例如:
var sample = ["A",2,6,8,34,90];
db.getCollection('source').aggregate([
{ "$match": { "my_list": { "$in": sample } } },
{ "$addFields": {
"score": {
"$add": [
{ "$cond": {
"if": {
"$eq": [
{ "$size": { "$setIntersection": [ "$my_list", sample ] }},
{ "$size": { "$literal": sample } }
]
},
"then": 100,
"else": 0
}},
{ "$sum": {
"$map": {
"input": "$my_list",
"as": "ml",
"in": {
"$multiply": [
{ "$indexOfArray": [
{ "$reverseArray": "$my_list" },
"$$ml"
]},
{ "$indexOfArray": [
{ "$reverseArray": { "$literal": sample } },
"$$ml"
]}
]
}
}
}}
]
}
}},
{ "$sort": { "score": -1 } }
])
会在顺序返回的文件是这样的:
/* 1 */
{
"_id" : 1.0,
"my_list" : [ "A", 2, 6, 8, 34, 90],
"score" : 155.0
}
/* 2 */
{
"_id" : 2.0,
"my_list" : ["A", "F", 2, 6, 19, 8, 90, 55],
"score" : 62.0
}
/* 3 */
{
"_id" : 3.0,
"my_list" : [ 90, 34, 8, 6, 3, "A"],
"score" : 15.0
}
的关键之处在于在使用$reverseArray
施加,从$indexOfArray
的值将是通过在匹配的索引产生“较大”从“第一个到最后一个”的顺序(颠倒过来)给出了一个更大的“权重”,以匹配数组开始处的匹配,而不是那些朝向结尾的匹配。
当然,你应该考虑的事情像第二个文件实际上包含的比赛“最”,有更多的数组项将放一个“更大的”权重初始比赛比第一文件内。
从上面的"A"
在第二个文档中得分高于第一个,因为尽管两个匹配的第一个位置都是"A"
,但数组的长度更长。但是也有一些影响,即"F"
是不匹配的,因此比它在后面的数组中具有更大的负面影响。最后一份文件中的"A"
同样适用,在阵列末尾,匹配对整体重量几乎没有影响。
考虑到这个问题的计数器是添加一些逻辑来考虑“完全匹配”的情况,例如这里的样本和当前数组的$setIntersection
的$size
比较。这将调整分数以确保匹配所有提供的元素的内容实际得分高于具有较少位置匹配的文档,但总体上具有更多元素。
随着“分数”的到位,您可以过滤掉结果(即$limit
)或其他可以应用的逻辑,以便仅返回所需的实际结果。但第一步是计算一个“分数”的工作。
所以这一切都一般主观什么逻辑,其实就是一个“最接近的匹配”,但$reverseArray
和$indexOfArray
操作一般都是关键,把“更重”在之前的索引相匹配,而不是最后一次。
总的来说你正在寻找逻辑的“计算”。聚合框架有一些可用的操作符,但实际应用的操作符取决于您的最终实现。我只是展示了一些“逻辑上起作用”的东西,但更重视数组比较中的“早期匹配”而不是“后者匹配”,当然还有数组实际上相同的“最重量”。
注意:可以使用的$unwind
的includeArrayIndex
选项没有上面使用的主要运营商早期版本的MongoDB来实现类似的逻辑。然而,该过程确实需要使用$unwind
来解构阵列,并且这会导致性能下降可能会否定操作的有效性。
实际上,“比较”是什么意思?你想比较集合中的每个文档与所有其他文档吗?或者您是否要求将提供的数组与文档中实际存储的数组进行比较?这些方法有很多不同的方法,因此您需要清楚您实际询问的是哪种情况。 –
我修改了这个问题。我提供了一个数组,并将搜索包含类似数组的文档的集合。 – danspants
迭代所有文档并在代码中使用某些逻辑来执行此操作,mongo未配置为使用这些逻辑。你将不得不为此设计算法。 –