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

Posted

技术标签:

【中文标题】mongodb获取具有最高价值的文档/子文档【英文标题】:mongodb get the document/subdocument having highest value 【发布时间】:2013-09-15 23:44:42 【问题描述】:

我有一个像这样的comment 收藏


  _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: []

这个想法是一个评论可以有很多回复。所有 cmets 和回复都有 idtextvotes。我怎样才能获得最好的 2 条评论或回复,获得最多的。在给定的情况下,这将是“回复 1”和“评论 2”。

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

但是,只有 1 个对 mongodb 的请求是否有可能,我可以得到这样的结果?

 [
   
     _id: 'r1',
     text: 'reply 1',
     isReply: true,
     votes: 3
   ,
   
     _id: 'c2',
     text: 'comment 2',
     votes: 2
   
 ]

或者更好的是我可以将评论/回复展平以获得按votes 排序的评论或回复列表吗? 在这种情况下,它将是 [r1, c2, c1, r2] 分别具有它们的属性

谢谢。


更新: 我尝试了aggregate($unwind: '$replies'),但我仍然有 2 个不同级别的 cmets 和回复,我无法通过使用聚合框架进行比较。也许有办法将这两个级别变平,我对 mongodb 很陌生。

【问题讨论】:

您能否编辑您的问题以包含您尝试过的聚合管道的详细信息?我想你可能需要做这样的事情:docs.mongodb.org/manual/tutorial/… 您需要所有属性还是仅其 id 和投票数就足够了?即 [id:'r1',votes:X 等]? @AsyaKamsky 我还需要结果示例中所述的其他属性。 【参考方案1】:

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

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

需要在 votes.v 上建立一个索引,因为它看起来像是一个阅读量很大的用例。更新 cmets 时,只需在同一更新请求中更新 votes 数组即可。

【讨论】:

如果我理解正确,这就是你会做的,因为我无法在评论中格式化代码我创建了一个 github gist here 。对我来说,要求 2 条最佳评论或回复似乎并不直接。请给我一个例子。 @lastid,你的要点对我来说看起来不错。我改进了我的答案,举了一个聚合查询的例子。 正如我的问题和要点中所述,我需要 2 条最佳评论或回复其内容(文本)。使用您的解决方案,您可以获得最好的 2 个 id,然后从这 2 个 id 中获取它们的内容对吗?所以你至少会有 2 个请求,也许 3 个。你的数据结构也很棘手,如果你只需要 1 个回复和它的投票,你需要从数组 replies 中获取回复i>votes 属性,然后做一个循环来知道哪个 votes 值是有问题的回复。我已经在我的问题中提出了一个包含 2 个请求的解决方案,我更喜欢这种方式,因为 votes 与每个回复或评论都有关联。 关于获取他们的内容,是的,你是对的。实际上,您的解决方案很有意义,但它涉及客户端合并。现在我们正在谈论数据库端解决方案。我的第一个想法是在 cmets 和回复中投票并将它们复制到另一个数组中。所以查询回复就像往常一样。根本问题是您希望在检索 cmets 和回复时将它们视为层次结构,并且在对它们进行投票时将它们视为相同的事物。所以数据模型必须是混合的。对吗? 如果投票是您最关心的,请将reply 作为 cmets 的***文档,并将回复的_ids 存储在comment 的数组中。因此获取 cmets 需要两个请求。顺便说一句,我认为没有一种简单的方法可以在当前设计的文档中仅获取一个数组中的一项,因为文档是处理的基本单元。【参考方案2】:

我建议您不要将回复放在评论对象中。 DbObject 的最大大小为 16mb。如果一个评论得到很多回复,这个结构就会失败。而不是这种结构,您可以将回复保留在评论集合中并将父评论 id 放入回复对象中(您可能希望放置像 type: 'reply' 或 type: 'comment' 这样的字段,但 parentCommentId 的存在将提供哪个是什么类型)。这样就可以轻松查询cmet和replies。

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

【讨论】:

如果我这样做,将花费我 2 个查询来显示前 10 个 cmets 及其回复。然后因为我利用 Meteor 中的反应性,我更容易在每个 comment 中嵌入 replies 我不知道聚合查询很慢...... 聚合查询可能会也可能不会很慢。这取决于是否有索引支持它们,以及它们做了​​多少工作。 UI 动作很慢,尤其是分组。

以上是关于mongodb获取具有最高价值的文档/子文档的主要内容,如果未能解决你的问题,请参考以下文章

如何使用php更新mongodb中具有键和值的子文档

如何使用php更新mongodb中具有键和值的子文档

获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)

在 MongoDB 中,何时使用简单的子文档,何时使用具有 2 字段元素的数组?

MongoDB聚合在Java中具有不同的价值?

如何从 mongodb 通过 Geowithin 获取匹配的子文档?