Mongo $ min和$ max,或者并行sorting

您好我想获得min和我的数据库中的字段的max

我发现这个解决scheme,查询和sorting的结果: 得到最大值的mongoose,我可以这样做两次,并将其与async.parallel合并写入非阻塞。 但我猜两个分贝查询可能不是最好的解决scheme。

第二个解决scheme是使用聚合。 但我不想分组。 我只想使用$match来过滤(过滤条件总是差异,可以{} )并运行与我的集合中的所有文档的查询。

http://docs.mongodb.org/manual/reference/operator/aggregation/min/ http://docs.mongodb.org/manual/reference/operator/aggregation/max/

题)

  1. 我可以在一个聚合查询运行这个,也许与$project
  2. 是否有另一种方法比aggregate没有分组工作
  3. 会1)/ 2)比sorting第一个解决scheme更有效率吗?

编辑:解决第一个解决scheme,但我认为有一个更有效的解决scheme,因为这需要两个数据库操作:

  async.parallel min: (next) -> ImplantModel.findOne(newFilter).sort("serialNr").exec((err, result) -> return next err if err? return next null, 0 if !result? next(null, result.serialNr) ) max: (next) -> ImplantModel.findOne(newFilter).sort("-serialNr").exec((err, result) -> return next err if err? return next null, 0 if !result? next(null, result.serialNr) ) (err, results) -> console.log results.min, ' ', results.max return callback(err) if err? return callback null, {min:results.min, max:results.max} ) 

不知道这个问题是什么,肯定没有从反应中得到真正的爱,但我不能让它去解决睡觉。

所以首先要说的是,我觉得我欠OP $ 10,因为我的预期结果并不是这样。

这里介绍的基本思想是比较:

  • 使用查询的并行执行来查找字段中的“最大值”(sorting后的总值)以及同一约束下的最小值

  • 汇总框架$max$min在整个集合上分组累加器。

在“理论”中,这两种select是完全一样的。 而在“理论”中,尽pipe并行执行可以通过同时向服务器发送请求,但是在这些请求中还是应该有一个“开销”,而客户端中的“聚合”function会将这两个结果放在一起。

这里的testing运行创build一个合理的密钥长度随机数据的“系列”执行,相比之下,“公平”的“关键”数据也是索引。

下一个“公平”阶段是通过对所有项目进行连续的“提取”来“加热”数据,以模拟将客户端机器能够将尽可能多的“工作集”数据加载到内存中。

然后,我们运行每个testing,进行比较和系列化,以避免与资源竞争,无论是“并行查询”还是“聚合”情况,都会在每次执行开始和结束时看到带有计时器的结果。

这里是我的testing脚本,基本的驱动程序,以保持事情尽可能瘦(nodejs环境考虑):

 var async = require('async'), mongodb = require('mongodb'), MongoClient = mongodb.MongoClient; var total = 1000000; MongoClient.connect('mongodb://localhost/bigjunk',function(err,db) { if (err) throw err; var a = 10000000000000000000000; db.collection('bigjunk',function(err,coll) { if (err) throw err; async.series( [ // Clean data function(callback) { console.log("removing"); coll.remove({},callback); }, // Insert data function(callback) { var count = 0, bulk = coll.initializeUnorderedBulkOp(); async.whilst( function() { return count < total }, function(callback) { var randVal = Math.floor(Math.random(a)*a).toString(16); //console.log(randVal); bulk.insert({ "rand": randVal }); count++; if ( count % 1000 == 0 ) { if ( count % 10000 == 0 ) { console.log("counter: %s",count); // log 10000 } bulk.execute(function(err,res) { bulk = coll.initializeUnorderedBulkOp(); callback(); }); } else { callback(); } }, callback ); }, // index the collection function(callback) { console.log("indexing"); coll.createIndex({ "rand": 1 },callback); }, // Warm up function(callback) { console.log("warming"); var cursor = coll.find(); cursor.on("error",function(err) { callback(err); }); cursor.on("data",function(data) { // nuthin }); cursor.on("end",function() { callback(); }); }, /* * *** The tests ** */ // Parallel test function(callback) { console.log("parallel"); console.log(Date.now()); async.map( [1,-1], function(order,callback) { coll.findOne({},{ "sort": { "rand": order } },callback); }, function(err,result) { console.log(Date.now()); if (err) callback(err); console.log(result); callback(); } ); }, function(callback) { console.log(Date.now()); coll.aggregate( { "$group": { "_id": null, "min": { "$min": "$rand" }, "max": { "$max": "$rand" } }}, function(err,result) { console.log(Date.now()); if (err) callback(err); console.log(result); callback(); } ); } ], function(err) { if (err) throw err; db.close(); } ); }); }); 

结果(与我所期望的相比)是在“总体情况”中进行调整。

对于10,000个文档

 1438964189731 1438964189737 [ { _id: 55c4d9dc57c520412399bde4, rand: '1000bf6bda089c00000' }, { _id: 55c4d9dd57c520412399c731, rand: 'fff95e4662e6600000' } ] 1438964189741 1438964189773 [ { _id: null, min: '1000bf6bda089c00000', max: 'fff95e4662e6600000' } ] 

这表明并行情况下的差值为6毫秒 ,聚合情况下的差值为32 毫秒

这能变好吗?

对于100,000个文档:

 1438965011402 1438965011407 [ { _id: 55c4dd036902125223a05958, rand: '10003bab87750d00000' }, { _id: 55c4dd066902125223a0a84a, rand: 'fffe9714df72980000' } ] 1438965011411 1438965011640 [ { _id: null, min: '10003bab87750d00000', max: 'fffe9714df72980000' } ] 

结果仍然清楚地显示了5ms ,这接近10倍数据的结果,并且在聚合情况下这是229ms慢,接近10倍(增加量)比前一个样本慢。

但是等一下,因为情况变得更糟。 让我们把样本增加到1,000,000个条目:

1,000,000文件样本:

 1438965648937 1438965648942 [ { _id: 55c4df7729cce9612303e39c, rand: '1000038ace6af800000' }, { _id: 55c4df1029cce96123fa2195, rand: 'fffff7b34aa7300000' } ] 1438965648946 1438965651306 [ { _id: null, min: '1000038ace6af800000', max: 'fffff7b34aa7300000' } ] 

这实际上是最差的,因为“平行”的情况仍然会持续5 毫秒的响应时间,现在“聚集”的情况已经爆发到2360ms (哇,超过2秒)。 与交替进近时间的差别只能被认为是完全不可接受的。 这是执行周期的500倍,而且计算量巨大

结论

除非你知道一个肯定的赢家,否则不要对某件事进行赌注。

聚合“应该”在这里赢得,因为结果背后的原则与基本algorithm中的“并行处理案例”基本相同,从可用索引的关键字中挑选结果。

这是一个“失败”(正如我的孩子喜欢说的),聚合pipe道需要由某人(我的“半伙伴”擅长这些东西)返回到“algorithm学校”并重新学习它的表兄弟正在使用的基础知识,以产生更快的结果。

所以这里的基本教训是:

  • 我们认为应该优化“总量”累加器来做到这一点,但目前显然不是。

  • 您希望以最快的方式来确定数据集合上的最小值/最大值 (不带和不同的键),那么使用.sort()修改器的并行查询实际上比任何替代方法都快得多。 (用索引)。

因此,对于希望通过数据集合执行此操作的人员,请使用此处显示的并行查询。 速度要快得多(直到我们可以教导操作员变得更好:>)


这里我要说的是, 所有的时机都是和硬件相关的,主要是这里比较有效的时序。

这些结果来自我的(古代)笔记本电脑

  • Core I7 CPU(8x内核)
  • Windows 7的主机(是的,不能打扰重新安装)
  • 8GB RAM主机
  • 4GB分配虚拟机(4x核心分配)
  • VirtualBox 4.3.28
  • Ubuntu 15.04
  • MongoDB 3.1.6(Devel)

以及列表中所需的最新“稳定”节点版本。