mongodb获取具有最高值的文档/子文档

mongodb获取具有最高值的文档/子文档,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我有一个像这样的评论集 { _id: 'c1', text: 'comment 1', votes: 1, replies: [ { _id: 'r1', text: 'reply 1', isReply: true, votes: 3 }, { _id: 'r2', text: 'reply 2', isReply: true, votes: 0 }

我有一个像这样的
评论集

{
  _id: 'c1',
  text: 'comment 1',
  votes: 1,
  replies: [
    {
      _id: 'r1',
      text: 'reply 1',
      isReply: true,
      votes: 3
    },
    {
      _id: 'r2',
      text: 'reply 2',
      isReply: true,
      votes: 0
    }
  ]
},
{
  _id: 'c2',
  text: 'comment2',
  votes: 2,
  replies: []
}
这个想法是一个评论可以有很多回复。所有评论和回复都有id、文本和投票。我怎样才能得到得票最多的最佳评论或回复。在给定的情况下,这将是“回复1”和“评论2”

我可以向mongodb发送一个请求以获得最好的2条评论,另一个请求获得最好的2条回复,然后比较它们以获得我想要的

但是,只需要向mongodb发出一个请求,我就可以得到这样的结果吗

 [
   {
     _id: 'r1',
     text: 'reply 1',
     isReply: true,
     votes: 3
   },
   {
     _id: 'c2',
     text: 'comment 2',
     votes: 2
   }
 ]
或者更好的方法是,我可以将评论/回复展平,以获得一个按投票数排序的评论或回复列表? 在这种情况下,它将是[r1,c2,c1,r2],分别具有它们的属性

谢谢


更新:
我尝试了
aggregate({$unwind:'$replays'})
但是我仍然有两个不同级别的评论和回复,我无法使用聚合框架进行比较。也许有一种方法可以将这两个级别变平,我对mongodb非常陌生。

我建议您不要将回复放在评论对象中。DbObject的最大大小为16mb。如果一条评论得到很多回复,那么这个结构就会失败。代替此结构,您可以将回复保留在注释集合中,并将父注释id放入回复对象中(您可能希望放入类似{type:'reply'}或{type:'comment'}的字段,但parentCommentId的存在将提供哪种类型的字段)。通过这种方式,您可以轻松地查询评论和回复


我还想补充一点,聚合查询不适合UI响应。我不知道您的用例,但不要忘记。

我建议您不要将回复放在评论对象中。DbObject的最大大小为16mb。如果一条评论得到很多回复,那么这个结构就会失败。代替此结构,您可以将回复保留在注释集合中,并将父注释id放入回复对象中(您可能希望放入类似{type:'reply'}或{type:'comment'}的字段,但parentCommentId的存在将提供哪种类型的字段)。通过这种方式,您可以轻松地查询评论和回复


我还想补充一点,聚合查询不适合UI响应。我不知道您的用例,但别忘了。

对模式进行一点更改以使投票非规范化将使排序更容易。如果评论文档中嵌入了另一个投票数组,如:

votes: [ 
  { "type" : "c", "_id": "c1", v: 1},
  { "type" : "r", "_id": "r1", v: 3},
  { "type" : "r", "_id": "r2", v: 2}
]
查询和排序可以是直接的

db.playground.aggregate(
[
  {$project: { votes: 1 }},
  {$unwind: "$votes"},
  {$sort: {"votes.v": -1}},
  {$limit: 2}
])
它给出了以下结果

{
  "result" : [
    {
      "_id" : "c1",
      "votes" : {
        "type" : "c",
        "_id" : "c1",
        "v" : 3
      }
    },
    {
      "_id" : "c1",
      "votes" : {
        "type" : "r",
        "_id" : "r1",
        "v" : 2
      }
    }
  ],
  "ok" : 1
}

需要一个关于vots.v的索引,因为它看起来像是一个阅读量很大的用例。更新注释时,只需在同一个更新请求中更新投票数组。

稍微更改模式以使投票非规范化将使排序更容易。如果评论文档中嵌入了另一个投票数组,如:

votes: [ 
  { "type" : "c", "_id": "c1", v: 1},
  { "type" : "r", "_id": "r1", v: 3},
  { "type" : "r", "_id": "r2", v: 2}
]
查询和排序可以是直接的

db.playground.aggregate(
[
  {$project: { votes: 1 }},
  {$unwind: "$votes"},
  {$sort: {"votes.v": -1}},
  {$limit: 2}
])
它给出了以下结果

{
  "result" : [
    {
      "_id" : "c1",
      "votes" : {
        "type" : "c",
        "_id" : "c1",
        "v" : 3
      }
    },
    {
      "_id" : "c1",
      "votes" : {
        "type" : "r",
        "_id" : "r1",
        "v" : 2
      }
    }
  ],
  "ok" : 1
}

需要一个关于vots.v的索引,因为它看起来像是一个阅读量很大的用例。更新评论时,只需在同一更新请求中更新投票数数组。

请编辑您的问题,以包含您尝试的聚合管道的详细信息?我想你可能需要这样做:你需要所有的属性,还是仅仅需要它的id和投票数就足够了?i、 e.[{id:'r1',投票数:X}等]?@AsyaKamsky我还需要结果示例中所述的其他属性。请编辑您的问题,以包含您尝试的聚合管道的详细信息,好吗?我想你可能需要这样做:你需要所有的属性,还是仅仅需要它的id和投票数就足够了?i、 e.[{id:'r1',voates:X}等]?@AsyaKamsky我还需要结果示例中所述的其他属性。如果我理解正确,您会这样做,因为我无法在注释中格式化代码,因为我创建了github gist。对我来说,要求最好的评论或答复似乎并不直接。“你能给我举个例子吗?”拉斯蒂德,我觉得你的要点不错。我改进了我的答案,给出了一个聚合查询的例子。正如我的问题和我的要点中所述,我需要两个最好的评论或回复,以及它们的内容(文本)。使用您的解决方案,您可以获得最好的两个ID,然后从这两个ID中获得正确的内容?因此,您将有至少2个请求,可能是3个。您的数据结构也很复杂,如果您只需要1个reply及其投票,则需要从数组reples和vots属性中获取回复,然后执行一个循环,以知道哪个vots值适用于所讨论的回复。我在问题中已经提出了两个请求的解决方案,我更喜欢这种方式,因为投票是每个回复或评论的纽带。关于获取内容,是的,你是对的。实际上,您的解决方案很有意义,但它涉及客户端合并。现在我们讨论的是数据库端解决方案。我的第一个想法是在评论和回复中拥有投票权,并将它们复制到另一个数组中。因此,查询回复与往常一样。根本的问题是,在检索评论和回复时,您希望将它们视为层次结构中的内容,在对它们进行投票时,也希望将它们视为相同的内容。因此,数据模型必须是混合的。对吗?如果投票是您最关心的,请将
回复
作为顶级文档作为注释,并将回复的
\u id
存储在
注释
中的数组中。因此,获得评论需要两个请求。顺便说一句,我不认为用您当前的设计在文档中只获取数组中的一项是一种简单的方法,因为文档是处理的基本单元。如果我理解正确,您会这么做,因为我无法在注释中格式化代码,我创建了github gist。对我来说,要求最好的评论或答复似乎并不直接。“你能给我举个例子吗?”拉斯蒂德,我觉得你的要点不错。我改进了我的答案,给出了一个聚合查询的例子