您好我想在我的数据库中获取字段的min
和max
值。
我找到了这个查询和排序结果的解决方案: get max value in mongoose 我可以做两次并将它与async.parallel结合起来,将其写成非阻塞。但我猜两个数据库查询可能不是最佳解决方案。
第二种解决方案是使用聚合。但我不想把任何事情分组。我只想使用$match
进行过滤(过滤条件总是差异,可以是{}
)并使用我的集合中的所有文档运行查询。
http://docs.mongodb.org/manual/reference/operator/aggregation/min/ http://docs.mongodb.org/manual/reference/operator/aggregation/max/
问题)
$project
aggregate
分组编辑: 解决了第一个解决方案,但我认为有一个更有效的解决方案,因为这需要两个数据库操作:
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}
)
答案 0 :(得分:2)
不知道这个问题究竟是什么,并且肯定不会从响应中得到真正的爱,但我不能让它继续睡觉而不解决。
所以首先要说的是我认为我欠这个10美元的OP,因为我的预期结果并非如此。
这里介绍的基本思想是对比:
在“理论”中,这两个选项完全相同。并且在“理论”中,即使并行执行可以“同时”发生并且同时向服务器发出请求,在这些请求中仍然应该存在“开销”继承,并且客户端中的“聚合”功能将两个结果结合在一起。
此处的测试运行“系列”执行,创建合理密钥长度的随机数据,比较“公平”,此处的“密钥”数据也被编入索引。
下一个“公平”阶段是通过对所有项目执行顺序“提取”来“预热”数据,以模拟将尽可能多的“工作集”数据加载到内存中,因为客户端计算机能够
然后我们运行每个测试,比较和系列,以便不与每个资源竞争资源,对于“并行查询”情况或“聚合”情况,以查看定时器附加到开始和结束的结果每次执行。
这是我的测试平台脚本,关于尽可能保持精简的基本驱动程序(考虑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 ms 与 32ms 的巨大差异。
这可以变得更好吗? 否强>:
100,000 文件:
1438965011402
1438965011407
[ { _id: 55c4dd036902125223a05958, rand: '10003bab87750d00000' },
{ _id: 55c4dd066902125223a0a84a, rand: 'fffe9714df72980000' } ]
1438965011411
1438965011640
[ { _id: null,
min: '10003bab87750d00000',
max: 'fffe9714df72980000' } ]
结果仍然清晰显示 5 ms ,这接近于数据减少10倍的结果,并且在聚合情况下, 229 ms 更慢,几乎是因子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' } ]
这实际上是最糟糕的,因为“并行”案例仍然表现出 5ms 响应时间,“聚合”案例现在已经爆发为高峰 2360ms (哇,超过2整秒)。这只是被认为是完全不可接受的,因为它与替代接近时间的差别。这是执行周期的500倍,并且在计算方面是巨大。
除非你知道肯定的赢家,否则永远不要打赌。
聚合“应该”在这里获胜,因为结果背后的原理基本上与基本算法中的“并行执行情况”相同,以从可用的索引的键中选择结果。
这是一个“失败”(正如我的孩子们喜欢说的)聚合管道需要由某人(我的“半伙伴”擅长这些东西)来回到“算法学校”并且重新学习它表现较差的基础知识,以产生更快的结果。
所以这里的基本教训是:
我们认为应该优化“聚合”累加器来做到这一点,但目前它们显然不是。
您希望最快方式确定数据集合上的 min / max (没有和不同的键),然后使用{执行并行查询{1}} modfier实际上比任何替代方案都快得多。 (带索引)。
因此,对于想要对数据集合执行此操作的人,请使用此处所示的并行查询。它要快得多(直到我们可以教操作员更好:&gt;)
我应该注意,所有时序都与硬件相关,主要是时间的“比较”,这里有效。
这些结果来自我的(古代)笔记本电脑
此处列表中所需的最新“稳定”节点版本。