Consider a collection consisting of documents of the following shape:
{
_id: ObjectId("…"),
items: [
{value: "abc", other: "other1"},
{value: "def", other: "other2"}
],
other: "other"
}
I want to transform all the documents in this collection into the following shape:
{
_id: ObjectId("…"),
items: [
{values: ["abc"], value: "abc", other: "other1"},
{values: ["def"], value: "def", other: "other2"}
],
other: "other"
}
where every subdocument in items
now has an extra array field values
which only holds the value
field value.
How can I achieve this transformation in an efficient way?
I tried the following query:
db.collection.find({}).forEach(function (doc) {
doc.items.forEach(function (item) {
item.values = [item.value];
});
db.collection.save(doc);
});
But it took quite a long time (the collection has 1.5M documents), so I'd like to know more efficient way (possibly using aggregation operations?).
CodePudding user response:
Maybe something like this :
db.collection.aggregate([
{
"$addFields": {
"items": {
"$map": {
"input": "$items",
"as": "i",
"in": {
values: [
"$$i.value"
],
value: "$$i.value",
other: "$$i.other"
}
}
}
}
}
])
Explained:
Add the value under the values array together with other array elements under $map/$in.
And here is the update query( mongoDB 4.2 ) that will fix all documents in your collection:
db.collection.update({},
[
{
"$addFields": {
"items": {
"$map": {
"input": "$items",
"as": "i",
"in": {
values: [
"$$i.value"
],
value: "$$i.value",
other: "$$i.other"
}
}
}
}
}
],
{
multi: true
})