Tobbenda
Tobbenda

Reputation: 103

MongoDB: Add field to all objects in array, based on other fields on same object?

I am fairly new to MongoDB and cant seem to find a solution to this problem. I have a database of documents that has this structure:

   {
      id: 1 
      elements: [ {elementId: 1, nr1: 1, nr2: 3}, {elementId:2, nr1:5, nr2: 10} ]
   }

I am looking for a query that can add a value nr3 which is for example nr2/nr1 to all the objects in the elements array, so that the resulting document would look like this:

  {
      id: 1 
      elements: [ {elementId: 1, nr1: 1, nr2: 3, nr3:3}, {elementId:2, nr1:5, nr2: 10, nr3: 2} ]
   }

So I imagine a query along the lines of this:

db.collection.updateOne({id:1}, {$set:{"elements.$[].nr3": nr2/nr1}})

But I cant find how to get the value of nr2 and nr1 of the same object in the array. I found some similar questions on stackoverflow stating this is not possible, but they were 5+ years old, so I thought maybe they have added support for something like this.

I realize I can achieve this with first querying the document and iterate over the elements-array doing updates along the way, but for the purpose of learning I would love to see if its possible to do this in one query.

Upvotes: 2

Views: 2050

Answers (2)

turivishal
turivishal

Reputation: 36104

You can use update with aggregation pipeline starting from MongoDB v4.2,

  • $map to iterate loop of elements
  • divide nr2 with nr1 using $divide
  • merge current object and new field nr3 using $mergeObjects
db.collection.updateOne(
  { id: 1 }, 
  [{
    $set: {
      elements: {
        $map: {
          input: "$elements",
          in: {
            $mergeObjects: [
              "$$this",
              { nr3: { $divide: ["$$this.nr2", "$$this.nr1"] } }
            ]
          }
        }
      }
    }
  }]
)

Playground

Upvotes: 3

user14775196
user14775196

Reputation:

db.collection.update(
  { id:1},
  { "$set": { "elements.$[elem].nr3":elements.$[elem].nr2/elements.$[elem].nr1} },
  { "multi": true }
);

I guess this should work

Upvotes: 0

Related Questions