Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 1094 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
MongoDB rename database field within array

#1
I need to rename `indentifier` in this:

{ "general" :
{ "files" :
{ "file" :
[
{ "version" :
{ "software_program" : "MonkeyPlus",
"indentifier" : "6.0.0"
}
}
]
}
}
}


I've tried

db.nrel.component.update(
{},
{ $rename: {
"general.files.file.$.version.indentifier" : "general.files.file.$.version.identifier"
} },
false, true
)

but it returns: `$rename source may not be dynamic array`.
Reply

#2
I had a similar problem. In my situation I found the following was much easier:

1. I exported the collection to json:

<!-- -->

mongoexport --db mydb --collection modules --out modules.json

2. I did a find and replace on the json using my favoured text editing utility.

3. I reimported the edited file, dropping the old collection along the way:

<!-- -->

mongoimport --db mydb --collection modules --drop --file modules.json


Reply

#3
I also would like rename a property in array: and I used thaht


db.getCollection('YourCollectionName').find({}).snapshot().forEach(function(a){
a.Array1.forEach(function(b){
b.Array2.forEach(function©{
c.NewPropertyName = c.OldPropertyName;
delete c["OldPropertyName"];
});
});
db.getCollection('YourCollectionName').save(a)
});


Reply

#4
Starting `Mongo 4.2`, [`db.collection.update()`](

[To see links please register here]

) can accept an aggregation pipeline, finally allowing the update of a field based on its own value:

// { 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" } }
// ] } } }

---

Literally, this `update`s documents by (re)`$set`ting the `"general.files.file"` array by `$map`ping its `"file"` elements `in` a `"version"` object containing the same `"software_program"` field and the renamed `"identifier"` field which contains what used to be the value of `"indentifier"`.

---

A couple additional details:

* The first part `{}` is the match query, filtering which documents to update (in this case all documents).

* The second part `[{ $set: { "general.files.file": { ... }}}]` is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline):
* [`$set`](

[To see links please register here]

) is a new aggregation operator which in this case replaces the value of the `"general.files.file"` array.
* Using a [`$map`](

[To see links please register here]

) operation, we replace all elements from the `"general.files.file"` array by basically the same elements, but with an `"identifier"` field rather than `"indentifier"`:
* `input` is the array to map.
* `as` is the variable name given to looped elements
* `in` is the actual transformation applied on elements. In this case, it replaces elements by a `"version"` object composed by a `"software_program"` and a `"identifier"` fields. These fields are populated by extracting their previous values using the `$$file.xxxx` notation (where `file` is the name given to elements from the `as` part).

Reply

#5
My proposal would be this one:


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.
])

However, this works only when array `general.files.file` has a single document only. Most likely this will not always be the case, then you can use this one:

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.
])

Reply

#6
For what it's worth, while it sounds awful to have to do, the solution is actually pretty easy. This of course depends on how many records you have. But here's my example:

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);
});


I iterate over my collection where the array is found and the "wrong" name is found. I then iterate over the sub collection, set the new value, delete the old, and update the whole document. It was relatively painless. Granted I only have a few tens of thousands of rows to search through, of which only a few dozen meet the criteria.

Still, I hope this answer helps someone!

Edit: Added `snapshot()` to the query. See why in the comments.

> You must apply `snapshot()` to the cursor before retrieving any documents from the database.
> You can only use `snapshot()` with unsharded collections.

**From MongoDB 3.4, `snapshot()` function was removed. So if using Mongo 3.4+ ,the example above should remove `snapshot()` function.**
Reply

#7
As mentioned in the documentation there is no way to directly rename fields within arrays with a single command. Your only option is to iterate over your collection documents, read them and update each with `$unset` old/`$set` new operations.
Reply

#8
The easiest and shortest solution using aggregate (Mongo 4.0+).

db.myCollection.aggregate([
{
$addFields: {
"myArray.newField": {$arrayElemAt: ["$myArray.oldField", 0] }
}
},
{$project: { "myArray.oldField": false}},
{$out: {db: "myDb", coll: "myCollection"}}
])

The problem using forEach loop as mention above is the very bad performance when the collection is huge.
Reply

#9
I had to face the issue with the same schema. So this query will helpful for someone who wants to rename the field in an embedded array.


db.getCollection("sampledocument").updateMany({}, [
{
$set: {
"general.files.file": {
$map: {
input: "$general.files.file",
in: {
version: {
$mergeObjects: [
"$$this.version",
{ identifer: "$$this.version.indentifier" },
],
},
},
},
},
},
},
{ $unset: "general.files.file.version.indentifier" },
]);

[Another Solution][1]


[1]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through