Javascript MongoDB:Map Reduce:从另一个子文档创建一个子文档

Javascript MongoDB:Map Reduce:从另一个子文档创建一个子文档,javascript,mongodb,mapreduce,mongodb-query,aggregation-framework,Javascript,Mongodb,Mapreduce,Mongodb Query,Aggregation Framework,我有一个mongodb集合,其中包含以下文档: { "_id" : ObjectId("safdsd435tdg54trgds"), "startDate" : ISODate("2013-07-02T17:35:01.000Z"), "endDate" : ISODate("2013-08-02T17:35:01.000Z"), "active" : true, "channels" : [ 1, 2, 3, 4 ], { "_id" : ObjectId("safdsd435td

我有一个mongodb集合,其中包含以下文档:

{
"_id" : ObjectId("safdsd435tdg54trgds"),
"startDate" : ISODate("2013-07-02T17:35:01.000Z"),
"endDate" : ISODate("2013-08-02T17:35:01.000Z"),
"active" : true,
"channels" : [ 
    1, 2, 3, 4
],
{
"_id" : ObjectId("safdsd435tdg54trgds"),
"startDate" : ISODate("2013-07-02T17:35:01.000Z"),
"endDate" : ISODate("2013-08-02T17:35:01.000Z"),
"active" : true,
"channels" : [ 
    1, 2, 3, 4
],
"tags" :[ 
            {
                "name": one
                "type": channel
            },
            {
                "name": two
                "type": channel
            },
            {
                "name": three
                "type": channel
            },
            {
                "name": four
                "type": channel
            }
        ]           
}
}

我想把它转换成这样的东西:

{
"_id" : ObjectId("safdsd435tdg54trgds"),
"startDate" : ISODate("2013-07-02T17:35:01.000Z"),
"endDate" : ISODate("2013-08-02T17:35:01.000Z"),
"active" : true,
"channels" : [ 
    1, 2, 3, 4
],
{
"_id" : ObjectId("safdsd435tdg54trgds"),
"startDate" : ISODate("2013-07-02T17:35:01.000Z"),
"endDate" : ISODate("2013-08-02T17:35:01.000Z"),
"active" : true,
"channels" : [ 
    1, 2, 3, 4
],
"tags" :[ 
            {
                "name": one
                "type": channel
            },
            {
                "name": two
                "type": channel
            },
            {
                "name": three
                "type": channel
            },
            {
                "name": four
                "type": channel
            }
        ]           
}

我已经有了1,2,3,4的映射。为了简单起见,我把它们按字母顺序排列。这些值可能不同,但它们是静态映射。

您似乎试图在不对集合进行大量迭代的情况下进行此更新,因此您可以使用mapReduce“完成”此操作,尽管使用的是非常“mapReduce方式”,因为它有自己的操作方式

因此,首先要定义一个封装当前文档的映射器:

var mapFunction=函数(){
var key=此参数。\u id;
var值={
开始日期:这个,开始日期,
endDate:this.endDate,
主动的,主动的,
频道:这个。频道
};
发射(键、值);
};
现在这里实际上不会调用reducer,因为映射器中的所有键都是唯一的,当然是原始文档中的
\u id
值。但为了让通话愉快:

var reduceFunction=function(){};
由于这是一个一对一的问题,因此将转到完成。它可能在映射器中,但为了清洁起见

var finalizeFunction=函数(键,reducedValue){
变量标记=[
{name:“one”,键入:“channel”},
{name:“two”,键入:“channel”},
{name:“three”,键入:“channel”},
{name:“four”,键入:“channel”}
];
reducedValue.tags=[];
reducedValue.channels.forEach(函数(通道){
reducedValue.tags.push(tags[channel-1]);
});
返回还原值;
};
然后调用mapReduce:

db.docs.mapReduce(
映射函数,
还原函数,
{ 
out:{replace:“newdocs”},
finalize:finalizef函数
}
)
这将输出到一个新集合,但以mapReduce的方式,您可以:

{
“_id”:ObjectId(“53112b2d0ceb66905ae41259”),
“价值”:{
“起始日期”:ISODate(“2013-07-02T17:35:01Z”),
“结束日期”:ISODate(“2013-08-02T17:35:01Z”),
“主动”:正确,
“通道”:[1,2,3,4],
“标签”:[
{
“名称”:“一”,
“类型”:“通道”
},
{
“姓名”:“两个”,
“类型”:“通道”
},
{
“名字”:“三个”,
“类型”:“通道”
},
{
“名字”:“四个”,
“类型”:“通道”
}
]
}
}
因此,除
\u id
之外的所有文档字段都被卡在该
值下,因此这不是您想要的文档。但这就是mapReduce的工作原理

如果你真的需要从这个出狱并且愿意等待一段时间,那么即将发布的2.6版本增加了一个管道阶段。因此,您可以通过以下方式“转换”新收藏中的文档:

db.newdocs.aggregate([
//转换文档
{“$project”:{
“开始日期”:“$value.startDate”,
“endDate”:“$value.endDate”,
“活动”:“$value.active”,
“频道”:“$value.channels”,
“标记”:“$value.tags”
}},
//输出到新集合
{“$out”:“fixeddocs”}
])
所以这是正确的。当然,这不是你原来的收藏。因此,要回到这种状态,您必须收集并使用:

db.newdocs.drop();
db.docs.drop();
db.fixeddocs.renameCollection(“文件”);
现在,请仔细阅读有关这方面的文档,有几个限制,当然您还必须重新创建索引

所有这些,尤其是最后一个阶段将导致大量磁盘抖动,同时请记住,您将在此处丢弃集合。几乎可以肯定的是,在执行此操作时离线访问数据库

即使如此,这里的危险也非常真实,也许您可以通过运行迭代循环来使用任意JavaScript更新文档。如果你真的必须这样做,你可以用在服务器上执行。但是如果您这样做,那么请仔细阅读文档

但为了完整性,即使我不提倡:

db.eval(函数(){
db.docs.find().forEach(函数(文档){
变量标记=[
{name:“one”,键入:“channel”},
{name:“two”,键入:“channel”},
{name:“three”,键入:“channel”},
{name:“four”,键入:“channel”}
];
document.tags=[];
document.channels.forEach(函数(通道){
document.tags.push(tags[channel-1]);
});
var id=文档。\u id;
删除文档。\u id;
更新({“\u id”:id},文档);
});
})

所有文档不一定都有通道的V值,所以当它是空值时,如何进行空检查而不进行迭代。@PiHorse也许最简单的方法是使用查询选择完全跳过它们:{“通道”:{“$exists”:true}。根据您选择的方法,您可能还需要反向条件来合并结果。