使用 DBCollection.mapReduce 更改 MongoDB schema: sururious nested "value" 属性



我需要创建一个数据库补丁,将MongoDB集合的所有元素更新为新格式。 例如,粗略简化,旧格式具有这样的文档:

{
"_id" : ObjectId("572a7f30200cd11355083cd9"),
"_class" : "Domain",
"oldAttribute": 123
}

新格式需要这样的文档:

{
"_id" : ObjectId("572a7f30200cd11355083cd9"),
"_class" : "Domain",
"newAttribute": 123
}

我正在使用MongoDB的Java API,数据库补丁也必须用Java编写,但是与其编写一堆Java代码来修改文档,首先读取文档然后写回文档,我认为我可以利用DBCollection.mapReduce()MapReduceCommand.OutputType.REPLACE直接在MongoDB中对一小段JavaScript做同样的事情。 这样:

myCollection.mapReduce(map, reduce, "myCollection", MapReduceCommand.OutputType.REPLACE, null);

对于map函数,我传递如下内容:

function () {
var copy = {'_id': this._id, '_class': this._class, newAttribute: this.oldAttribute};
emit(this._id, copy);
}

从技术上讲,reduce函数永远不应该被调用,因为键是唯一的,所以我只是在那里传递一个虚拟函数。

这似乎有效,但存在一个问题:应用 map-reduce 后,集合中的所有文档现在都有一个嵌套的value属性:

{
"_id": { "$oid" : "56c2371a200cd11088252111"},
"value":
{
"_id": { "$oid" : "56c2371a200cd11088252111"},
"_class": "Domain",
"newAttribute": 123.0
}
}

(此输出是从 Java 控制台粘贴的,因此格式略有不同)

简而言之,我的问题是:如何摆脱嵌套的value属性并将所有属性(包括_id)置于顶层?

如果要就地修改文档,可以使用带有$rename修饰符的更新。 使用multi:true运行更新将更新集合中的每个文档。

如果希望更改显示为"原子"并且集合未分片,则可以将aggregate$out和以下管道一起使用:

db.collection.aggregate([ 
{$project:{_class:1, newAttribute:"$oldAttribute"}}, 
{$out:"collection"}
]) 

提供与原始集合名称相同的$out名称会将集合替换为其新转换的版本。

如果要在不删除旧版本的情况下创建集合的新版本,则只需为$out提供新的集合名称即可。

最新更新