Reputation: 21381
Disclaimer: Even though similar, not the same as MongoDB rename database field within array.
I want to change the key of a field from name
to title
with database commands and NOT the shell. I found out that using $rename is not possible inside an array. So I turned to $set and $unset and created this:
db.runCommand({
update: 'apps',
updates: [
{
q: {versions: {$elemMatch: {title: {$exists: false}}}},
u: {
$set: {'versions.$.title': '$name'}
},
multi: true
},
{
q: {versions: {$elemMatch: {name: {$exists: true}}}},
u: {
$unset: {'versions.$.name': ''}
},
multi: true
}
]
})
This works somewhat. It does all I want but it changes every title/name to the string "$name" instead of the value of the field name
.
I also tried this:
db.runCommand({
update: 'apps',
updates: [
{
q: {versions: {$elemMatch: {title: {$exists: false}}}},
u: {
$set: {
versions: {
$map: {
input: "versions",
as: 'each',
in: {
"title": "$$each.name"
}
}
}
}
},
multi: true
},
{
q: {versions: {$elemMatch: {name: {$exists: true}}}},
u: {
$unset: {'versions.$.name': ''}
},
multi: true
}
]
})
But that just results in [The dollar ($) prefixed field '$map' in 'versions.$map' is not valid for storage.]
. How would I go about renaming a field inside an array?
Below is a minified version of my apps collection for reference. I literally only want to change every key called name
into title
.
[{
identifier: "x",
versions: [
{
name: "test_name"
version: "x.x.x"
},
{
name: "test_name"
version: "x.x.x"
},
]
},
{
identifier: "y",
versions: [
{
name: "test_name2"
version: "x.x.x"
},
{
name: "test_name2"
version: "x.x.x"
},
]
}, ... ]
Upvotes: 1
Views: 575
Reputation: 36104
But that just results in
The dollar ($) prefixed field '$map' in 'versions.$map' is not valid for storage.
.
$map
's input
accepts reference field using $
sign $version
,u
object in array bracket for update with an aggregation pipelinetitle
and version
in $map
$unset
is not required because $map
will replace old data with new fields in in
db.runCommand({
update: 'apps',
updates: [
{
q: { "versions.name": { $exists: true } },
u: [{
$set: {
versions: {
$map: {
input: "$versions",
in: {
"title": "$$this.name",
"version": "$$this.version"
}
}
}
}
}],
multi: true
}
]
})
Second way, For more dynamic approach
$mergeObjects
inside $map
, to prevent manual list of key-values pair$unset
stage to remove name
field from version
arraydb.runCommand({
update: 'apps',
updates: [
{
q: { "versions.name": { $exists: true } },
u: [
{
$set: {
versions: {
$map: {
input: "$versions",
in: {
$mergeObjects: [
"$$this",
{ "title": "$$this.name" }
]
}
}
}
}
},
{ $unset: "versions.name" }
],
multi: true
}
]
})
Upvotes: 3