对嵌入文档数量的记录进行排序

时间:2014-08-11 07:27:20

标签: javascript node.js mongodb sorting mongoose

我正在使用mongodb和mongoose,我有一个用户创建评级和评论的情况,我想要的是获取对评论得票最多的产品的评论。是否可以在mongo中进行?

结构是

{ "product" : ObjectId("53ccfa53b502542b2f463acd"),
  "_id" : ObjectId("53e8675aea39355818ec4ab2"),
  "vote" : [ ],
  "review" : "Blah Blah Blah",
  "stars" : 3,
  "email" : "user@example.com", "__v" : 0 }

现在我想显示已经获得最多票数的评论,我知道如果在find()之后我放了sort()和limit()函数,它可以通过同一文档级别上的字段实现但是我在这种情况下不知道如何处理多个记录'投票' ....

2 个答案:

答案 0 :(得分:2)

你能做的最好的事情就是维持一个" voteCount"在文件本身。原因将在一瞬间变得明显。

您可以在向阵列中添加或删除成员时对其进行维护。我们假设您正在使用ObjectId以及$push$pull更新运算符来执行此操作。因此,您$inc还有一些查询逻辑,以确保您不会复制" User ObjectId"投票。假设一个名为" Product"的模型:

Product.update(
    {
        "_id": ObjectId("53e8675aea39355818ec4ab2"),
        "votes": { "$ne": ObjectId("53e87caaca37ffa384e5a931") }, // the user ObjectId
    },
    {
        "$push": { "votes": ObjectId("53e87caaca37ffa384e5a931" }, // same Id
        "$inc": { "voteCount": 1 }
    },
    function(err) {

    }
);

并删除:

Product.update(
    {
        "_id": ObjectId("53e8675aea39355818ec4ab2"),
        "votes": ObjectId("53e87caaca37ffa384e5a931"), // the user ObjectId
    },
    {
        "$pull": { "votes": ObjectId("53e87caaca37ffa384e5a931" }, // same Id
        "$inc": { "voteCount": -1 }
    },
    function(err) {

    }
);

然后,这只是在现场排序的问题:

Product.find().sort({ "voteCount": -1 }).limit(1).exec(function(err,doc) {


});

但如果由于某种原因你看不出合适的话来保持" voteCount"在文档中,您需要手动"项目"这与聚合框架。使用具有MongoDB 2.6或更高版本的$size聚合方法:

Product.aggregate(
    [
        { "$project": {
            "product": 1,
            "vote": 1,
            "review": 1,
            "stars": 1,
            "email": 1,
            "voteCount": { "$size": "$vote" }
        }},
        { "$sort": { "voteCount": -1 } },
        { "$limit": 1 }
    ],
    function(err,result) {

    }
);

或者通过数组上的$unwind并通过$sum获取早期版本的计数:

Product.aggregate(
    [
        { "$unwind": "$vote"
        { "$group": {
            "_id": "$_id",
            "product": { "$first": "$product" },
            "vote": { "$push": "$vote" },
            "review": { "$first": "$review" },
            "stars": { "$first": "$stars" },
            "email": { "$first": "$email" },
            "voteCount": { "$sum": 1 }
        }},
        { "$sort": { "voteCount": -1 } },
        { "$limit": 1 }
    ],
    function(err,result) {

    }
);

除非你真的需要除数组长度之外的其他计算,否则聚合方法实际上没有多大意义。最好将它保存在文档中。

答案 1 :(得分:1)

使用MongoDB的最佳方法是添加新的计数器字段以明确存储投票数:

{ "product" : ObjectId("53ccfa53b502542b2f463acd"),
  "_id" : ObjectId("53e8675aea39355818ec4ab2"),
  "vote" : [ {...}, {...}, {...} ],
  "vote_count": 3, // <-- new field
  "review" : "Blah Blah Blah",
  "stars" : 3,
  "email" : "user@example.com", "__v" : 0 }

当然,您还有其他选择,例如使用Aggregation Pipeline。但添加新字段是最佳选择,因为它允许您在此字段上构建索引并进行索引查询。