我们开始在2.0使用Mongo。作为我们经常运行的查询的一部分,我们运行map / reduce作业,这些作业也会在这些作业执行时从其他集合中提取数据。
自mongo 2.4以来,此功能已被删除(http://docs.mongodb.org/manual/release-notes/2.4/#additional-limitations-for-map-reduce-and-where-operations),唯一的建议是“重构您的代码”。
那么,有没有办法重构代码?我知道这是一个普遍的问题,但我要求一般性的申请。涉及的集合和交叉查询的大小和使用有足够的多样性。
此时,我甚至会采用一个补丁,只将db
对象带回服务器代码范围。似乎以下补丁就足够了(是的,我知道它具有这些安全隐患,但我甚至不使用分片。这是我们重新获得我们依赖的功能的最快方式):
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index 742392f..225a2b7 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -623,6 +623,7 @@ namespace mongo {
void State::init() {
// setup js
_scope.reset(globalScriptEngine->getPooledScope( _config.dbname, "mapreduce" ).release() );
+ _scope->localConnect( _config.dbname.c_str() );
if ( ! _config.scopeSetup.isEmpty() )
_scope->init( &_config.scopeSetup );
答案 0 :(得分:3)
从概念上讲,MapReduce仅对输入文档集和发出的值进行操作。严格来说,执行数据库操作超出了MapReduce作业的范围。有关更改原因的详细信息,请参阅SERVER-8104和SERVER-3130。
话虽如此,提供的补丁应该可以使用,但是由于锁定的影响(以及上述安全问题),我会提醒您不要使用它。
关于如何重构可能在过去版本中使用此功能的代码的一般化问题,我想到的一个建议是使用多个利用“减少”输出类型的MapReduce作业。 incremental MapReduce的文档可能会对您有所帮助。
如果目标是服务器端执行,另一个选项可能是将MapReduce逻辑重构为可以使用db.eval()执行的脚本。由于问题的性质,这可能是一个有点复杂的练习。
答案 1 :(得分:2)
听起来你正在描述加入2个集合的必要性。我在过去成功完成了这项工作并编写了一个示例,其中包括来自data.gov和cia.gov的测试数据:
http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/
这种方法有两个主要的注意事项:
然后,只需在减速器中组合发出的文件即可。这样做可以很好地跨分片进行扩展,甚至可以跨核心进行本地扩展(参见https://jira.mongodb.org/browse/SERVER-4258)。
答案 2 :(得分:0)
我知道很老的问题,为了别人的利益而在这里登录。这适用于2.6.4。
根据您的要求,您仍可以在mapreduce期间从其他馆藏中获取文档。您可以声明dbref并从您的收藏中获取数据。尽管文档说$ id字段需要是id,但我在那里尝试过标准的mongo查询并且似乎正在工作。基于dbref文档,您可以指向不同的DB,尽管我还没有尝试过。
以下是我的地图功能的一个简化示例,其中我从其他两个集合中获取数据,并且没有任何常用字段名称
function() {
var values = {
providerAccount: this,
};
if (!(typeof(this['lastStatusLogId']) === 'undefined')) {
var v = new Object();
v["$ref"] = "statuslog";
v["$id"] = new ObjectId(this['lastStatusLogId']);
values['lastStatusLog'] = v;
}
v = new Object();
v["$ref"] = "provider";
v["$id"] = new ObjectId(this.providerId);
values["provider"] = v;
emit(this._id, values);
}