Mongo自定义多键排序

时间:2012-03-22 13:08:02

标签: node.js mongodb sorting multikey nosql

Mongo docs州:

  

Mongo multikey功能可以自动索引值数组。

那太好了。但是如何基于多键进行排序呢?更具体地说,如何根据数组匹配百分比对集合进行排序

例如,我有一个模式[ 'fruit', 'citrus' ]和一个集合,如下所示:

{
    title: 'Apples',
    tags: [ 'fruit' ]
},

{
    title: 'Oranges',
    tags: [ 'fruit', 'citrus' ]
},

{
    title: 'Potato',
    tags: [ 'vegetable' ]
}

现在,我想根据每个条目与标签模式的匹配百分比对集合进行排序。橘子必须先到,苹果第二,土豆最后。

最有效和最简单的方法是什么?

2 个答案:

答案 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' ]}传递,以便它们在上面的地图函数中可用。