【问题标题】:Add some kind of row number to a mongodb aggregate command / pipeline将某种行号添加到 mongodb 聚合命令/管道
【发布时间】:2016-05-12 12:03:53
【问题描述】:

这个想法是将一种行号返回给 mongodb 聚合命令/管道。类似于我们在 RDBM 中的内容。

它应该是一个唯一的数字,如果它与行/数字完全匹配并不重要。

对于这样的查询:

[ { $match: { "author" : { $ne: 1 } } }, { $limit: 1000000 } ]

我想回来:

{ "rownum" : 0, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }
{ "rownum" : 1, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }
{ "rownum" : 2, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }
{ "rownum" : 3, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }
{ "rownum" : 4, "title" : "Iliad", "author" : "Homer", "copies" : 10 }

是否可以在mongodb中生成这个rownum?

【问题讨论】:

  • 不,这是不可能的。你最好解释一下“你为什么认为你需要这个”。它通常用于分页结果的 SQL 实现中,例如在对项目进行排序时。如果您更愿意解释要解决的用例,可能还有其他选择。
  • 这是一个改进——当数据量很大时,在从 MongoDB 数据源获取数据的 BI 工具上使用字符串作为 id 确实是个坏主意,> 100mio。没有真正的解决方法,除非...
  • 向 MongoDB 中的行添加数字(无论如何您都不能这样做)意味着传递所有结果/数据(大概在选择“页面”之前)并一次分配一个。因此,由于架构做事的方式,绝不可能是一种改进。我给了你选择。 1.接受“不,不能做”。 2. 解释您的用例,并可能获得比您目前所能想到的更好的替代方法。在我看来,一个是死胡同,而另一个可能只是去某个地方。

标签: mongodb mongodb-query aggregation-framework row-number


【解决方案1】:

不确定大查询中的性能,但这至少是一种选择。

您可以通过分组/推送将结果添加到数组中,然后使用includeArrayIndex 展开,如下所示:

[
  {$match: {author: {$ne: 1}}},
  {$limit: 10000},
  {$group: {
    _id: 1,
    book: {$push: {title: '$title', author: '$author', copies: '$copies'}}
  }},
  {$unwind: {path: '$book', includeArrayIndex: 'rownum'}},
  {$project: {
    author: '$book.author',
    title: '$book.title',
    copies: '$book.copies',
    rownum: 1
  }}
]

现在,如果您的数据库包含大量记录,并且您打算分页,您可以使用 $skip 阶段,然后使用 $limit 10 或 20 或任何您希望每页显示的内容,然后添加来自将 $skip 阶段添加到您的 rownum 中,您将获得真正的位置,而无需推送所有结果来枚举它们。

【讨论】:

【解决方案2】:

另一种方法是使用 "$function" 跟踪 row_number

[{ $match: { "author" : { $ne: 1 } }}  , { $limit: 1000000 },
{
    $set: {
      "rownum": {
        "$function": {
          "body": "function() {try {row_number+= 1;} catch (e) {row_number= 0;}return row_number;}",
          "args": [],
          "lang": "js"
        }
      }
    }
  }]

我不确定这是否会搞砸一些事情!

【讨论】:

    【解决方案3】:

    从Mongo 5 开始,这是新的$setWindowFields 聚合运算符及其$documentNumber 操作的完美用例:

    // { x: "a" }
    // { x: "b" }
    // { x: "c" }
    // { x: "d" }
    db.collection.aggregate([
      { $setWindowFields: {
        sortBy: { _id: 1 },
        output: { rowNumber: { $documentNumber: {} } }
      }}
    ])
    // { x: "a", rowNumber: 1 }
    // { x: "b", rowNumber: 2 }
    // { x: "c", rowNumber: 3 }
    // { x: "d", rowNumber: 4 }
    

    $setWindowFields 允许我们在了解之前或之后文档的情况下处理每个文档。这里我们只需要$documentNumber提供的文档在整个集合(或聚合中间结果)中的位置信息。

    请注意,我们按_id 排序,因为sortBy 参数是必需的,但实际上,由于您不关心行的顺序,它可以是任何您想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      • 2018-07-07
      • 1970-01-01
      • 2018-08-20
      • 1970-01-01
      • 2015-05-25
      相关资源
      最近更新 更多