Home > Net >  MongoDB: How to insert a singleton array with a value in every nested field?
MongoDB: How to insert a singleton array with a value in every nested field?

Time:11-22

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.

Playground_aggregate

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

Playground_update

  • Related