Mongo 2.4 - 在服务器端代码中使db对象可用(map / reduce)

时间:2013-05-02 17:40:52

标签: mongodb

我们开始在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 );

3 个答案:

答案 0 :(得分:3)

从概念上讲,MapReduce仅对输入文档集和发出的值进行操作。严格来说,执行数据库操作超出了MapReduce作业的范围。有关更改原因的详细信息,请参阅SERVER-8104SERVER-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/

这种方法有两个主要的注意事项:

  1. 集合之间的连接条件需要是发出的密钥。
  2. 发出的文件形状应该相同。
  3. 然后,只需在减速器中组合发出的文件即可。这样做可以很好地跨分片进行扩展,甚至可以跨核心进行本地扩展(参见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);
  }