Marcel Morgan
Marcel Morgan

Reputation: 78

Mongo use $set to add new field which copies a nested array object's value

I want to use $set to copy a value which is nested in an array of objects to each object, but instead of copying that single value, it projects all the elements in an array. This is what I tried:

db.things.insertOne(
  {
    name: 'first',
    items: [
      { value: 1 },
      { value: 2 }
    ]
  }
)
db.things.updateMany(
  {},
  [
    {"$set": {"items.value_copy": "$items.value"}}
  ]
)

Outcome:

{
  "_id": {
    "$oid": "5e527707f3ae2e9f7adb6e1c"
  },
  "name": "first",
  "items": [
    {
      "value": 1,
      "value_copy": [
        1,
        2
      ]
    },
    {
      "value": 2,
      "value_copy": [
        1,
        2
      ]
    }
  ]
}

Expected outcome:

{
  "_id": {
    "$oid": "5e527707f3ae2e9f7adb6e1c"
  },
  "name": "first",
  "items": [
    {
      "value": 1,
      "value_copy": 1
    },
    {
      "value": 2,
      "value_copy": 2
    }
  ]
}
db.version();

4.2.3

Any idea how to get to my intended goal?

Upvotes: 2

Views: 1388

Answers (2)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17915

That issue is because $items.value would get a list of values at items.values from all documents. You can use aggregation pipeline in update operation, Which is introduced in MongoDB v4.2 to re-write the entire items array with new field added to its each object :

db.thingsNew.update({}, [{
    $set: {
        items: {
            $map: {
                input: "$items",
                as : 'each',
                in: {
                    "value": "$$each.value",
                    "value_copy": "$$each.value"
                }
            }
        }
    }
}], { multi: true })

Upvotes: 2

Valijon
Valijon

Reputation: 13103

Not possible

Walkaround. We use MongoDb Aggregation with $map to add value_copy field and $out operator override the collection.

db.things.aggregate([
  {
    $set: {
      items: {
        $map: {
          input: "$items",
          in: {
            "value": "$$this.value",
            "value_copy": "$$this.value"
          }
        }
      }
    }
  },
  {
    $out: "things"
  }
])

Upvotes: 0

Related Questions