您似乎正在尝试在不对您的集合进行大量迭代的情况下进行此更新,因此您“可以”使用 mapReduce 进行此操作,尽管采用非常“mapReduce 方式”,因为它有自己的做事方式。
所以首先你要定义一个 mapper 来封装你当前的文档:
var mapFunction = function (){
var key = this._id;
var value = {
startDate: this.startDate,
endDate: this.endDate,
active: this.active,
channels: this.channels
};
emit( key, value );
};
现在这里实际上不会调用 reducer,因为 mapper 中的所有键都是唯一的,当然是 reducer 中的 _id 值em>原件文件。但是为了让通话愉快:
var reduceFunction = function(){};
因为这是一个一对一的事情,这将进入finalize。它可能在 mapper 中,但为了清洁起见
var finalizeFunction = function (key, reducedValue) {
var tags = [
{ name: "one", type: "channel" },
{ name: "two", type: "channel" },
{ name: "three", type: "channel" },
{ name: "four", type: "channel" }
];
reducedValue.tags = [];
reducedValue.channels.forEach(function(channel) {
reducedValue.tags.push( tags[ channel -1 ] );
});
return reducedValue;
};
然后调用mapReduce:
db.docs.mapReduce(
mapFunction,
reduceFunction,
{
out: { replace: "newdocs" },
finalize: finalizeFunction
}
)
所以这将输出到一个新集合,但是以 mapReduce 的方式,所以你有这个:
{
"_id" : ObjectId("53112b2d0ceb66905ae41259"),
"value" : {
"startDate" : ISODate("2013-07-02T17:35:01Z"),
"endDate" : ISODate("2013-08-02T17:35:01Z"),
"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 之外的所有文档字段都卡在value 字段下,因此这不是您想要的文档。但这就是 mapReduce 的工作原理。
如果您真的需要越狱并愿意等待,即将发布的 2.6 版本添加了 $out 管道阶段。因此,您“可以”使用$project 转换新集合中的文档,如下所示:
db.newdocs.aggregate([
// Transform the document
{"$project": {
"startDate": "$value.startDate",
"endDate": "$value.endDate",
"active": "$value.active",
"channels": "$value.channels",
"tags": "$value.tags"
}},
// Output to new collection
{"$out": "fixeddocs" }
])
所以那是对的。但这当然不是您的原始收藏。所以要回到那个状态,你将不得不 .drop() 集合并使用 .renameCollection() :
db.newdocs.drop();
db.docs.drop();
db.fixeddocs.renameCollection("docs");
现在请阅读关于此的文档,有一些限制,当然您还必须重新创建索引。
所有这一切,特别是最后一个阶段将导致 很多 磁盘抖动,同时请记住,您在这里丢弃了集合。几乎可以肯定的是,在执行此操作时会离线访问您的数据库。
即便如此,这里的危险也足够真实,也许你可以忍受运行一个迭代循环来更新文档,使用任意 JavaScript。如果你真的必须这样做,你总是可以使用db.eval() 来让所有这些都在服务器上执行。但是如果你这样做了,那么请仔细阅读文档。
但为了完整性,即使我不提倡这样做:
db.eval(function(){
db.docs.find().forEach(function(document) {
var tags = [
{ name: "one", type: "channel" },
{ name: "two", type: "channel" },
{ name: "three", type: "channel" },
{ name: "four", type: "channel" }
];
document.tags = [];
document.channels.forEach(function(channel) {
document.tags.push( tags[ channel -1 ] );
});
var id = document._id;
delete document._id;
db.docs.update({ "_id": id },document);
});
})