javascript - Mongo 聚合游标和计数

标签 javascript node.js mongodb mongodb-query

根据 mongodb node driver docs 聚合函数现在返回一个游标(从 2.6 开始)。

我希望我可以使用它来获取预先限制和跳过的项目数,但在创建的游标上似乎没有任何计数功能。如果我在 mongo shell 中运行相同的查询,光标有一个 itcount 函数,我可以调用它来获取我想要的。

我看到创建的游标有一个 on data 事件(这是否意味着它是 CursorStream ?)它似乎被触发了预期的次数,但是如果我将它与 cursor.get 结合使用,则没有结果被传递到回调函数中.

新的游标功能可以用于统计聚合查询吗?

编辑代码:

在 mongo shell 中:

> db.SentMessages.find({Type : 'Foo'})
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).count()
3

> db.SentMessages.find({Type : 'Foo'}).limit(1)
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).limit(1).count();
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).count()
2014-08-12T14:47:12.488+0100 TypeError: Object #<Object> has no method 'count'

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).itcount()
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ]).itcount()
1

> exit
bye

在 Node 中:
var cursor = collection.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ], { cursor : {}});

cursor.get(function(err, res){
  // res is as expected (1 doc)
});

cursor.count() 不存在

cursor.itcount() 不存在

on data 事件存在:
cursor.on('data', function(){
    totalItems++;
});

但是当与 cursor.get 结合使用时,.get 回调函数现在包含 0 个文档

编辑 2:返回的光标似乎是 aggregation cursor 而不是文档中列出的光标之一

最佳答案

对于那些可能会搜索此内容的人来说,这可能值得一个完整的解释,因此为后代添加一个。

具体返回的是 node.js 的事件流,它有效地包装了 stream.Readable接口(interface)与几个方便的方法。一个 .count()目前不是其中之一,考虑到当前使用的界面没有多大意义。

类似于 .stream() 返回的结果可用于游标对象的方法,当您考虑实现时,“计数”在这里没有多大意义,因为它旨在作为“流”进行处理,最终您将到达“结束”,否则只想处理直到到达那里。

如果您考虑过驱动程序中的标准“Cursor”接口(interface),则聚合游标不相同的原因有很多:

  • 游标允许在执行之前处理“修饰符”操作。这些属于 .sort() 的类别, .limit().skip() .所有这些实际上在管道中指定的聚合框架中都有对应的指令。作为可能出现在“任何地方”而不仅仅是作为简单查询的后处理选项的管道阶段,提供相同的“光标”处理没有多大意义。
  • 其他光标修饰符包括特殊的,如 .hint() , .min().max()这是对“索引选择”和处理的更改。虽然这些可能对聚合管道有用,但目前没有简单的方法将它们包含在查询选择中。大多数情况下,上一点的逻辑会覆盖对“光标”使用相同类型接口(interface)的任何点。

  • 其他考虑因素是您实际想要用游标做什么以及为什么“想要”返回一个游标。由于游标通常是“单程旅行”,因为它们通常只被处理直到到达终点并且在可用的“批次”中,因此可以得出合理的结论,即“计数”实际上只是在末尾,当实际上“队列”最终耗尽时。

    虽然事实上标准的“光标”实现确实有一些技巧,但主要原因是这只是扩展了“元”数据概念,因为查询分析引擎必须“扫描”一定数量的文档才能确定哪个在结果中返回的项目。

    不过,聚合框架稍微利用了这个概念。因为不仅有与通过标准查询分析器处理的结果相同的结果,而且还有额外的阶段。这些阶段中的任何一个都有可能“修改”实际在要处理的“流”中返回的结果“计数”。

    同样,如果您想从学术的 Angular 来看这一点,并说“当然,查询引擎应该保留计数的‘元数据’,但我们可以不跟踪之后修改的内容吗?”。这将是一个公平的论点,管道运营商如 $match $group $unwind 甚至可能包括 $project 和新的 $redact ,所有这些都可以被认为是一个合理的案例,用于在每个管道阶段保持自己对“处理的文档”的跟踪,并在可能返回的“元数据”中更新它以解释完整的管道结果计数。

    最后一个论点是合理的,但也要考虑到目前为聚合管道结果实现“游标”概念是 MongoDB 的一个新概念。可以公平地说,在第一个设计点的所有“合理”期望都是组合文档的“大多数”结果不会限制 BSON 限制的大小。但随着使用范围的扩大,人们的看法会发生变化,事情也会发生变化以适应。

    所以这个“可能”可能会改变,但这不是“当前”实现的方式。虽然 .count()在标准游标实现上可以访问记录扫描数字的“元数据”,当前实现上的任何方法都将导致检索所有游标结果,就像 .itcount() 一样。在 shell 中。

    通过计算“数据”事件并在最后发出一些东西(可能是 JSON 流生成器)作为“计数”来处理“光标”项目。对于任何需要“预先”计数的用例,无论如何它似乎都不是游标的有效用途,因为输出肯定是一个合理大小的整个文档。

    关于javascript - Mongo 聚合游标和计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25239408/

    相关文章:

    javascript - d3 js 知道一个 svg 形状是否有一个类

    javascript - 覆盖 Backbone.Wreqr.radio 处理程序

    javascript - 如何显示我的 MongoDB 属性?

    javascript - 重置旧的点击元素rel

    javascript - 使用浏览器后退按钮返回时如何将对象作为 Prop 传递给先前的 react 组件( react , react 路由器)

    node.js - NowJS 中的安全性

    node.js - 为什么我的应用程序不能在 Heroku 上建立 websocket 连接?

    javascript - 快速路由器.route : 404 Error

    node.js - 我是否必须在 axios 配置中声明数据

    mongodb - Mongoose 过期属性无法正常工作