【问题标题】:Mongodb node.js $out with aggregation only working if calling toArray()Mongodb node.js $out 聚合仅在调用 toArray() 时才有效
【发布时间】:2018-09-24 21:25:26
【问题描述】:

使用"mongodb": "^3.0.6" 保存聚合查询作为$out 运算符的结果仅在调用.toArray() 时有效。

聚合步骤:

let aggregationSteps = [{
    $group: {
        _id: '$created_at',
    }
}, {'$out': 'ProjectsByCreated'}];

执行聚合:

await collection.aggregate(aggregationSteps, {'allowDiskUse': true})

预期结果:名为 ProjectsByCreated 的新集合。

结果:没有集合,查询没有抛出异常但没有被执行? (只需 1 毫秒)

附加 toArray() 会产生预期的行为:

await collection.aggregate(aggregationSteps, {'allowDiskUse': true}).toArray();

为什么 mongodb 只在调用 .toArray() 时创建结果集合,文档在哪里这么说?我怎样才能解决这个问题?

文档似乎没有提供有关此的任何信息:

【问题讨论】:

  • 非常好的问题。听起来聚合正在返回一个游标,并且在您遍历游标(例如,使用 .toArray() 添加)之前,聚合不会写出到 ProjectsByCreated 集合中。这听起来很没有帮助!如果您尝试other cursor methods,您是否调查过会发生什么?
  • @VinceBowdren 手动迭代光标 - 伪代码:while(cursor.hasNext()) 生成输出集合 - 仅关闭光标也不起作用。

标签: node.js mongodb aggregation-framework


【解决方案1】:

MongoDB 承认这种行为,但他们也表示这是按设计工作的。

它已在 MongoDB JIRA $out aggregation stage doesn't take effect 中记录为错误,并且响应说这不是错误:

这种行为是有意的,并且在一段时间内没有通过节点驱动程序改变。当您通过调用 Collection.prototype.aggregate “运行”聚合时,我们创建了一个中间游标,它在请求某种 I/O 之前不会执行。这允许我们提供可链接的游标 API(例如 cursor.limit(..).sort(..).project(..)),在执行初始查询之前在构建器中构建查找或聚合选项。

... 链接 toArray 以执行 out 阶段感觉不太正确。有没有更自然的东西我没有注意到?

不幸的是,那里的链接方法只是继续构建您的聚合。以下任何方法都将导致运行初始聚合:toArray、each、forEach、hasNext、next。我们曾考虑为变更流之类的内容添加类似 exec/run 的内容,但它仍在我们的积压工作中。现在,理论上你可以只调用 hasNext 来运行第一个聚合并检索第一批(这很可能是 exec/run 无论如何都会在内部执行的操作)。

所以,看起来您必须调用其中一种方法来开始迭代光标,然后$out 才会执行任何操作。正如您已经在做的那样,添加.toArray() 可能是最安全的。请注意,to.Array() 不会像往常一样将整个结果加载到 RAM 中;因为它包含$outthe aggregation returns an empty cursor

【讨论】:

  • 我仍然觉得它应该自动创建集合。我将使用 .toArray() 函数 - 谢谢 :)
  • 我和你在一起。这就是为什么我想知道是否有其他人同意我们并将其作为一个错误报告给 MongoDB 自己。我确信这种设计选择的根本原因在技术上是有意义的,但这种行为仍然令人沮丧。
  • 我建议使用hasNext 而不是toArray,因为它可以避免将整个结果加载到 RAM 中并构建数组。如果我们只想触发执行,toArray 有点过头了,不是吗?
  • @Christallkeks :谢天谢地,如果你有 $out 在管道中,它只有 returns an empty cursor。没有将整个结果加载到内存中的危险。
  • @Christallkeks 我已经编辑了我的答案以包括关于返回空光标的评论,以解决您的评论。如果您对更新后的问题感到满意,现在很高兴删除我们的 cmets?
【解决方案2】:

因为Aggregation 操作返回的是游标,而不是结果。 为了从光标处返回所有文档,我们需要使用toArray方法。

【讨论】:

  • 不清楚为什么当输出被写入另一个带有 $out 的集合时,聚合应该返回一个游标;您会认为这会自动发生,无需客户进行任何额外活动。
  • @VinceBowdren 这很有趣,感谢您提供的信息!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-30
  • 2021-09-08
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多