您没有提到您使用的是哪个版本的 MongoDB,但无论如何,解决方案将与此处介绍的类似。我将在 Ubuntu 13.04 附带的 2.2.4 之上进行演示。
这样做的问题确实是将选项注入游标。这就是addOption
生活的地方:
> var cursor = db.test.find()
> cursor.addOption
function (option) {
this._options |= option;
return this;
}
让我们看看是如何mapReduce
定义的:
> db.test.mapReduce
function (map, reduce, optionsOrOutString) {
var c = {mapreduce:this._shortName, map:map, reduce:reduce};
...
var raw = this._db.runCommand(c);
...
return new MapReduceResult(this._db, raw);
}
因此,它构建了一个文档以通过runCommand
. 让我们进一步研究一下:
> db.runCommand
function (obj) {
if (typeof obj == "string") {
var n = {};
n[obj] = 1;
obj = n;
}
return this.getCollection("$cmd").findOne(obj);
}
所以命令是通过findOne
. 让我们研究一下:
> db.test.findOne
function (query, fields, options) {
var cursor = this._mongo.find(this._fullName, this._massageObject(query) || {}, fields, -1, 0, 0, options || this.getQueryOptions());
if (!cursor.hasNext()) {
return null;
}
var ret = cursor.next();
...
return ret;
}
啊,这里有一些有趣的东西。光标正在使用来自参数的标志进行初始化options
,不幸的是,这对您的情况没有帮助,因为runCommand
它未设置,但它与getQueryOptions()
来自集合的 进行 OR 运算。让我们研究一下:
> db.collection.getQueryOptions
function () {
var options = 0;
if (this.getSlaveOk()) {
options |= 4;
}
return options;
}
哎。。不好说。所以我们无法访问游标,也无法通过非黑客手段将查询选项注入到执行的命令中。
好吧,但是我们已经了解了很多关于 map reduce 命令实际上是如何通过该过程传递到服务器的。它只是针对数据库中特定集合查询的文档。这意味着我们可以构建相同的查询并自己运行它,但需要提供任何必要的标志。
我不会讨论构建整个 MongoDB 命令并为您设置结果的麻烦,但我只会通过使用isMaster
命令向您展示它实际上是有效的。
这是没有任何标志运行的命令:
> db.getCollection("$cmd").findOne({isMaster: 1}).ismaster
true
要查看效果上的差异,我们将 tcpdump 与数据库的通信。我们可以在有线协议文档中看到,相关标志位于集合名称之前,以 32 位整数形式存在,因此很容易发现转储的相关部分:
. vvvvvvvvv
0x0040: d407 0000 0000 0000 7465 7374 2e24 636d ........test.$cm
0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i
好的。我们可以看到四个字节被归零,就在集合名称之前。
现在,让我们在提供一些标志的同时做同样的事情。我们从上面的调试部分了解到,查询标志可以作为 的第三个选项提供findOne
,所以让我们这样做:
> db.getCollection("$cmd").findOne({isMaster: 1}, undefined, 0xBEEF).ismaster
true
并查看转储:
. vvvvvvvvv
0x0040: d407 0000 efbe 0000 7465 7374 2e24 636d ........test.$cm
0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i
嘿,我们的标志被传递到了应该的地方,我们还可以看到它被反转了,这意味着字节被编码为 little-endian,与docs匹配。
因此,这意味着您可以提供标志DBQuery.Option.noTimeout
作为 的第三个选项,并按照文档findOne
中描述的方式手动编码 map-reduce 命令,方法与我们对 的操作类似,您将得到您想要的。isMaster