带有聚合的Mongodb node.js $ out仅在调用toArray()时有效 [英] Mongodb node.js $out with aggregation only working if calling toArray()

查看:124
本文介绍了带有聚合的Mongodb node.js $ out仅在调用toArray()时有效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用$out运算符保存使用"mongodb": "^3.0.6"的聚合查询仅在调用.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()时才创建结果集合,文档在哪里说明呢?我怎样才能解决这个问题?

该文档似乎未提供有关此信息:

解决方案

MongoDB承认这种行为,但他们也说这是按设计要求工作的.

它已被记录为MongoDB JIRA中的错误, $ out聚合阶段不需​​要,并且回答说这不是错误:

此行为是故意的,并且在一段时间内未随节点驱动程序更改.当您通过调用Collection.prototype.aggregate运行"聚合时,我们将创建一个中介Cursor,该游标在请求某种I/O之前不会执行.这样,我们就可以提供可链接的游标API(例如,cursor.limit(..).sort(..).project(..)),并在执行初始查询之前在构建器中构建find或聚集选项.

...为了执行out阶段而链接到Array感觉不太正确.有没有更自然的东西我没注意到?

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

因此,看来您必须调用一种方法来开始迭代游标,然后$out会执行任何操作.正如您已经在做的那样,添加.toArray()可能是最安全的.请注意,to.Array()不会像往常一样将整个结果加载到RAM中.因为它包含$out,所以聚合返回空游标.

Saving an aggregation query using "mongodb": "^3.0.6" as result with the $out operator is only working when calling .toArray().

The aggregation step(s):

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

Executing the aggregation:

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

Expected result: New collection called ProjectsByCreated.

Result: No collection, query does not throw an exception but is not being executed? (takes only 1ms)

Appending toArray() results in the expected behaviour:

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

Why does mongodb only create the result collection when calling .toArray() and where does the documentation tell so? How can I fix this?

The documentation doesn't seem to provide any information about this:

解决方案

MongoDB acknowledge this behaviour, but they also say this is working as designed.

It has been logged as a bug in the MongoDB JIRA, $out aggregation stage doesn't take effect, and the responses say it is not a fault:

This behavior is intentional and has not changed in some time with the node driver. When you "run" an aggregation by calling Collection.prototype.aggregate, we create an intermediary Cursor which is not executed until some sort of I/O is requested. This allows us to provide the chainable cursor API (e.g. cursor.limit(..).sort(..).project(..)), building up the find or aggregate options in a builder before executing the initial query.

... Chaining toArray in order to execute the out stage doesn't feel quite right. Is there something more natural that I haven't noticed?

Unfortunately not, the chained out method there simply continues to build your aggregation. Any of the following methods will cause the initial aggregation to be run: toArray, each, forEach, hasNext, next. We had considered adding something like exec/run for something like change streams, however it's still in our backlog. For now you could theoretically just call hasNext which should run the first aggregation and retrieve the first batch (this is likely what exec/run would do internally anyway).

So, it looks like you do have to call one of the methods to start iterating the cursor before $out will do anything. Adding .toArray(), as you're already doing, is probably safest. Note that to.Array() does not load the entire result into RAM as normal; because it includes a $out, the aggregation returns an empty cursor.

这篇关于带有聚合的Mongodb node.js $ out仅在调用toArray()时有效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆