在Mongo中,我如何仅显示共享密钥的最高值的文档?

时间:2014-04-13 21:53:39

标签: mongodb meteor mongodb-query

假设我在名为“Store”的集合中有以下四个文档:

{ item: 'chair', modelNum: 1154, votes: 75 }
{ item: 'chair', modelNum: 1152, votes: 16 }
{ item: 'table', modelNum: 1017, votes: 24 }
{ item: 'table', modelNum: 1097, votes: 52 }

我想找到每种商品类型的票数最多的文件。 这个简单示例的结果将返回modelNum:1154和modelNum:1097。根据客户输入的投票得分,向我展示最受欢迎的椅子和桌子模型。

编写此查询并按降序投票对其进行排序的最佳方法是什么?我正在使用流星开发,但我不认为这会产生影响。

Store.find({????}).sort({votes: -1});

3 个答案:

答案 0 :(得分:1)

您可以使用$first$last聚合运算符来实现您的目标。这些运算符仅在$group$sort后有用。使用$first的示例:

db.collection.aggregate([
    // Sort by "item" ASC, "votes" DESC
    {"$sort" : {item : 1, votes : -1}}, 
    // Group by "item" and pick the first "modelNum" (which will have the highest votes)
    {"$group" : {_id : "$item", modelNum : {"$first" : "$modelNum"}}}
])

这是输出:

{
        "result" : [
                {
                        "_id" : "table",
                        "modelNum" : 1097
                },
                {
                        "_id" : "chair",
                        "modelNum" : 1154
                }
        ],
        "ok" : 1
}

答案 1 :(得分:1)

如果您希望在Meteor和客户端上执行此操作,我只需使用每个循环和基本查找。 Minimongo将数据保存在内存中,因此我认为额外的find调用并不昂贵。

像这样:

 Template.itemsList.helpers({
   items: function(){
     var itemNames = Store.find({}, {fields: {item: 1}}).map( 
       function( item ) { return item.item; }
     );
     var itemsMostVotes = _.uniq( itemNames ).map( 
       function( item ) {
         return Store.findOne({item: item}, {sort: {votes: -1}});
       }
     );
     return itemsMostVotes;
   }
 });

我已经切换到findOne所以这会返回一个对象数组,而不是find那样的光标。如果您真的想要光标,那么您可以使用itemMostVotes中的_ids查询minimongo。

您也可以使用underscore groupBy and sortBy函数执行此操作。

答案 2 :(得分:0)

您需要使用聚合框架。

所以

db.Store.aggregate(
    {$group:{_id:"$item", "maxVotes": {$max:"$votes"}}}
);