使用 DBCollection.mapReduce 更改 MongoDB 架构:虚假嵌套 "value" 属性
Using DBCollection.mapReduce to change MongoDB schema: spurious nested "value" attribute
我需要创建一个数据库补丁,将 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
来用一小段 Java直接在MongoDB里面写脚本,像这样:
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 modifier. Running update with multi:true
将更新集合中的每个文档。
如果您希望更改出现 "atomic" 并且集合不分片,您可以使用 aggregate
和 $out
以及此管道:
db.collection.aggregate([
{$project:{_class:1, newAttribute:"$oldAttribute"}},
{$out:"collection"}
])
向 $out
提供与原始集合名称相同的名称将用它的新转换版本替换该集合。
如果你想创建新版本的集合而不删除旧版本,那么只需给$out
一个新的集合名称即可。
我需要创建一个数据库补丁,将 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
来用一小段 Java直接在MongoDB里面写脚本,像这样:
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 modifier. Running update with multi:true
将更新集合中的每个文档。
如果您希望更改出现 "atomic" 并且集合不分片,您可以使用 aggregate
和 $out
以及此管道:
db.collection.aggregate([
{$project:{_class:1, newAttribute:"$oldAttribute"}},
{$out:"collection"}
])
向 $out
提供与原始集合名称相同的名称将用它的新转换版本替换该集合。
如果你想创建新版本的集合而不删除旧版本,那么只需给$out
一个新的集合名称即可。