update specific element from nested document array mongodb where has two matches

379 Views Asked by At

I need to update or create if not exist, specific obj,set score.b1 =50 and total=100 where object match curse=5 block=2

{ "_id":"sad445"
  "year":2020,
  "grade":4,
  "seccion":"A",
    "id": 100,
  "name": "pedro",
  "notes":[{"curse":5, 
          "block":1, 
          "score":{ "a1": 5,"a2": 10, "a3": 15},
          "total" : 50
          },{
          "curse":5, 
          "block":2, 
          "score":{ "b1": 10,"b2": 20, "b3": 30},
          "total" : 20
          }
   ]
}

I can update all obj but I need to update or create specific elem from the score and not all. and/or create objs "notes":[{curse, block and score}] if notes is empty notes:[]

notas.UpdateMany(
{"$and":[{"_id":"sad445"},{"notes":{"$elemMatch":{"curse":5,"block":3}}}]},

{"$set":{"updated_at":{"$date":{"$numberLong":"1620322881360"}},

"notes.$.score":{"vvkzo":15,"i2z4i":2,"i2z4i|pm":5},
"notes.$.total":100}},

{"multiple":false})
2

There are 2 best solutions below

4
On BEST ANSWER

Demo - https://mongoplayground.net/p/VaE28ujeOPx

Use $ (update)

The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.

the positional $ operator acts as a placeholder for the first element that matches the query document, and

the array field must appear as part of the query document.

db.collection.update({
  "notes": {
    "$elemMatch": { "block": 2, "curse": 5 }
  }
},
{
  $set: { "notes.$.score.b4": 40 }
})

Read upsert: true

Optional. When true, update() either:

Creates a new document if no documents match the query. For more details see upsert behavior. Updates a single document that matches the query. If both upsert and multi are true and no documents match the query, the update operation inserts only a single document.

To avoid multiple upserts, ensure that the query field(s) are uniquely indexed. See Upsert with Unique Index for an example.

Defaults to false, which does not insert a new document when no match is found.


Update

Demo - https://mongoplayground.net/p/iQQDyjG2a_B

Use $function

db.collection.update(
    { "_id": "sad445" },
    [
      {
        $set: {
          notes: {
            $function: {
              body: function(notes) {
                        var record = { curse:5, block:2, score:{ b4:40 } };
                        if(!notes || !notes.length) { return [record]; } // create new record and return in case of no notes
                        var updated = false;
                        for (var i=0; i < notes.length; i++) {
                            if (notes[i].block == 2 && notes[i].curse == 5) { // check condition for update
                                updated = true;
                                notes[i].score.b4=40; break; // update here
                            }
                        }
                        if (!updated) notes.push(record); // if no update push the record in notes array
                        return notes;
                    },
              args: [
                "$notes"
              ],
              lang: "js"
            }
          }
        }
      }
    ]
)
0
On

Try to add upsert: true.

Creates a new document if no documents match the query. Updates a single document that matches the query.

notas.UpdateMany(
{"$and":[{"_id":"sad445"},{"notes":{"$elemMatch":{"curse":5,"block":3}}}]},

{"$set":{"updated_at":{"$date":{"$numberLong":"1620322881360"}},

"notes.$.score":{"vvkzo":15,"i2z4i":2,"i2z4i|pm":5},
"notes.$.total":100}},

{"multiple":false, "upsert":true})