Arrays MongoDB重命名数组中的数据库字段
我需要在此重命名Arrays MongoDB重命名数组中的数据库字段,arrays,json,mongodb,rename,Arrays,Json,Mongodb,Rename,我需要在此重命名标识符: { "general" : { "files" : { "file" : [ { "version" : { "software_program" : "MonkeyPlus", "indentifier" : "6.0.0" } } ] } } } 我试过了 db.nrel.comp
标识符
:
{ "general" :
{ "files" :
{ "file" :
[
{ "version" :
{ "software_program" : "MonkeyPlus",
"indentifier" : "6.0.0"
}
}
]
}
}
}
我试过了
db.nrel.component.update(
{},
{ $rename: {
"general.files.file.$.version.indentifier" : "general.files.file.$.version.identifier"
} },
false, true
)
但它返回:
$rename source可能不是动态数组
如文档中所述,无法使用单个命令直接重命名数组中的字段。您唯一的选择是迭代收集文档,阅读它们并使用$unset
old/$set
新操作更新每个文档。尽管不得不这样做听起来很糟糕,但解决方案其实相当简单。这当然取决于你有多少记录。但以下是我的例子:
db.Setting.find({ 'Value.Tiers.0.AssetsUnderManagement': { $exists: 1 } }).snapshot().forEach(function(item)
{
for(i = 0; i != item.Value.Tiers.length; ++i)
{
item.Value.Tiers[i].Aum = item.Value.Tiers[i].AssetsUnderManagement;
delete item.Value.Tiers[i].AssetsUnderManagement;
}
db.Setting.update({_id: item._id}, item);
});
我迭代我的集合,在那里找到数组,发现“错误”的名称。然后迭代子集合,设置新值,删除旧值,并更新整个文档。这是相对无痛的。当然,我只有数万行要搜索,其中只有几十行符合条件
尽管如此,我还是希望这个答案能帮助一些人
编辑:向查询中添加了snapshot()
。请在评论中查看原因
在从数据库检索任何文档之前,必须对光标应用snapshot()
。
只能将snapshot()
用于未分片的集合
从MongoDB 3.4中删除了
snapshot()
函数。因此,如果使用Mongo 3.4+,上面的示例应该删除snapshot()
函数。我也遇到了类似的问题。在我的情况下,我发现以下几点要容易得多:
我还想重命名数组中的一个属性:我使用了thaht
db.getCollection('YourCollectionName').find({}).snapshot().forEach(function(a){
a.Array1.forEach(function(b){
b.Array2.forEach(function(c){
c.NewPropertyName = c.OldPropertyName;
delete c["OldPropertyName"];
});
});
db.getCollection('YourCollectionName').save(a)
});
启动
Mongo 4.2
,可以接受聚合管道,最后允许根据字段自身的值更新字段:
// { general: { files: { file: [
// { version: { software_program: "MonkeyPlus", indentifier: "6.0.0" } }
// ] } } }
db.collection.updateMany(
{},
[{ $set: { "general.files.file": {
$map: {
input: "$general.files.file",
as: "file",
in: {
version: {
software_program: "$$file.version.software_program",
identifier: "$$file.version.indentifier" // fixing the typo here
}
}
}
}}}]
)
// { general: { files: { file: [
// { version: { software_program: "MonkeyPlus", identifier: "6.0.0" } }
// ] } } }
从字面上说,这个
更新s文档的方法是(re)$set
通过$map
ping其“文件”
元素在“版本”
对象中,包含相同的“软件程序”
字段和重命名的“标识符”
字段,其中包含过去是“标识符”值的内容。
另外还有几个细节:
- 第一部分是匹配查询,过滤要更新的文档(在本例中为所有文档)
- 第二部分是更新聚合管道(注意方括号表示使用聚合管道):
- 是一个新的聚合运算符,在本例中,它将替换
“general.files.file”
数组的值
- 使用一个操作,我们用基本相同的元素替换
“general.files.file”
数组中的所有元素,但使用“identifier”
字段而不是“indicator”
:
input
是要映射的数组
as
是给定给循环元素的变量名
中的是应用于元素的实际转换。在这种情况下,它用一个“version”
对象替换元素,该对象由“software\u program”
和“identifier”
字段组成。这些字段是通过使用$$file.xxxx
符号提取它们以前的值来填充的(其中file
是作为部分的元素的名称)
我的建议是:
db.nrel.component.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $set: { "general.files.file": ["$general.files.file"] } },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])
db.nrel.componen.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $group: { _id: "$_id", general_new: { $addToSet: "$general.files.file" } } },
{ $set: { "general.files.file": "$general_new" } },
{ $unset: "general_new" },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])
但是,这仅在数组general.files.file
只有一个文档时有效。很可能情况并非总是如此,那么您可以使用此选项:
db.nrel.component.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $set: { "general.files.file": ["$general.files.file"] } },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])
db.nrel.componen.aggregate([
{ $unwind: "$general.files.file" },
{
$set: {
"general.files.file.version.identifier": {
$ifNull: ["$general.files.file.version.indentifier", "$general.files.file.version.identifier"]
}
}
},
{ $unset: "general.files.file.version.indentifier" },
{ $group: { _id: "$_id", general_new: { $addToSet: "$general.files.file" } } },
{ $set: { "general.files.file": "$general_new" } },
{ $unset: "general_new" },
{ $out: "nrel.component" } // carefully - it replaces entire collection.
])
$rename
不会扩展数组,@Alexander Azarov,有什么解决方法吗?我听说有人会复制到$rename可以进入的字段中…我个人正在编写脚本,遍历集合并进行迁移如果您希望使用数据库命令执行此操作:坚持使用MongoDB。。。这样的事情让我很难过:(我并不反对。我想这是相对容易实现的结果。我想这应该是公认的答案。我在几个收藏中使用了这种方法,每个收藏多达1200万份文档,效果非常好!绝对如此。这非常有效。遗憾的是MongoDB还不能在本机中包含这种行为。最好使用snapshot():db.Setting.find({'Value.Tiers.0.AssetUnderManagement':{$exists:1}}).snapshot().forEach(…)
否则您可能会陷入无限循环。另请参阅我的新循环。感谢详细信息,@PatrycjaK!更新我的答案。@Andrew Samuelsen我认为这应该是选定的答案-一个解决“按设计”问题的脚本问题我有点怀疑这种方法在大数据集上的效果如何。假设我的数据库是5gb,这个过程听起来很慢。或者我没有使用正确的文本编辑工具=-}也要小心实时数据库。如果在执行这些步骤时添加/修改了记录,更改将丢失。如果您只有在笔记本电脑上运行,但如果您在生产环境中工作,这不是一个可行的解决方案。从MongoDB 4.0开始,您还可以添加if(b.hasOwnProperty(“xxx”))用于验证属性或数组是否存在。您需要手动保留软件\u程序
。但如果版本字段有许多子字段,并且每个文档中可能有不同的字段,该怎么办?