Mongo multikey功能可以自动索引值数组。
那太好了。但是如何基于多键进行排序呢?更具体地说,如何根据数组匹配百分比对集合进行排序?
例如,我有一个模式[ 'fruit', 'citrus' ]
和一个集合,如下所示:
{
title: 'Apples',
tags: [ 'fruit' ]
},
{
title: 'Oranges',
tags: [ 'fruit', 'citrus' ]
},
{
title: 'Potato',
tags: [ 'vegetable' ]
}
现在,我想根据每个条目与标签模式的匹配百分比对集合进行排序。橘子必须先到,苹果第二,土豆最后。
最有效和最简单的方法是什么?
答案 0 :(得分:4)
从MongoDB 2.1开始,可以使用聚合框架进行类似的计算。语法类似于
db.fruits.aggregate(
{$match : {tags : {$in : ["fruit", "citrus"]}}},
{$unwind : "$tags"},
{$group : {_id : "$title", numTagMatches : {$sum : 1}}},
{$sort : {numTagMatches : -1}} )
返回
{
"_id" : "Oranges",
"numTagMatches" : 2
},
{
"_id" : "Apples",
"numTagMatches" : 1
}
由于两个原因,这应该比map-reduce方法快得多。首先是因为实现是本机C ++而不是javascript。其次,因为“$ match”会过滤掉根本不匹配的项目(如果这不是您想要的,您可以省略“$ match”部分,并将“$ sum”部分更改为1或0取决于标签是否等于“水果”或“柑橘”或两者都不是。
唯一需要注意的是mongo 2.1不推荐用于生产。如果你在生产中运行,你需要等待2.2。但是如果你只是自己试验,你可以使用2.1,因为聚合框架应该更高效。
答案 1 :(得分:2)
注意:Mongo 2.0及更早版本需要以下说明。对于更高版本,您应该考虑新的聚合框架。
我们在尝试模糊匹配我们索引的输入句子时做类似的事情。每次获得匹配时,您都可以使用map reduce发出对象ID,并将它们相加。然后,您需要将结果加载到客户端,然后按最高值排序。
db.plants.mapReduce(
function () {
var matches = 0;
for (var i = 0; i < targetTerms.length; i++) {
var term = targetTerms[i];
for (var j = 0; j < this.tags.length; j++) {
matches += Number(term === this.tags[j]);
}
}
emit(this._id, matches);
},
function (prev, curr) {
var result = 0;
for (var i = 0; i < curr.length; i++) {
result += curr[i];
}
return result;
},
{
out: { inline: 1 },
scope: {
targetTerms: [ 'fruit', 'oranges' ],
}
}
);
您可以使用地图缩减调用中的['fruit', 'citrus' ]
参数将scope
输入值作为{targetTerms: ['fruit', 'citrus' ]}
传递,以便它们在上面的地图函数中可用。