【问题标题】:Sorting records on number of embedded documents对嵌入文档数量的记录进行排序
【发布时间】:2017-06-27 17:24:09
【问题描述】:

我正在使用 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() 函数,它可以通过存在于同一文档级别的字段来实现,但是我在这种情况下不知道如何处理多条记录'投票'....

【问题讨论】:

  • 我的意思是内置方法,我可以写更长的代码,但想知道是否有这样的内置功能或模块...

标签: javascript node.js mongodb sorting mongoose


【解决方案1】:

您能做的最好的事情是在文档本身上维护一个“voteCount”。原因很快就会变得显而易见。

您可以在数组中添加或删除成员时保持这一点。假设您正在使用 ObjectId 和 $push$pull 更新运算符来执行此操作。因此,您还 $inc 使用一些查询逻辑来确保您不会重复投票的“用户对象 ID”。假设一个名为“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) {

    }
);

除非您确实需要除数组长度之外的其他计算,否则聚合方法的实现实际上并没有那么大的意义。所以最好把它保存在文档中。

【讨论】:

    【解决方案2】:

    使用 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。但是添加新字段是最好的选择,因为它可以让您在该字段上建立索引并进行索引查询。

    【讨论】:

      猜你喜欢
      • 2012-02-11
      • 2019-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      相关资源
      最近更新 更多