1

This is the structure i have, i want to update the nested array element if an object key matches for example - i want to match grnno :"10431000" and update the other keys of that object like vehicle_no,invoice_no etc.

{
    "_id" : ObjectId("5f128b8aeb27bb63057e3887"),
    "requirements" : [ 
        {
            "grns" : [ 
                {
                    "invoice_no" : "123",
                    "vehicle_no" : "345",
                    "req_id" : "5f128c6deb27bb63057e388a",
                    "grnno" : "10431000"
        },
        {
                    "invoice_no" : "abc",
                    "vehicle_no" : "def",
                    "req_id" : "5f128c6deb27bb63057e388a",
                    "grnno" : "10431001"
        }
          ]
       }
    ]
}

I have tried this code

 db.po_grn.update({
                "requirements.grns.grnno":"10431001"
            }, {
                $set: {
                    "requirements.$.grns": {"invoice_no":"test",vehicle_no:"5455"}
                }
            })

But this is changing the structure i have like this

 "requirements" : [ 
        {
            "grns" : {
                "invoice_no" : "test",
                 "vehicle_no":"5455"

            },
            "req_id" : ObjectId("5f128b8aeb27bb63057e3886")
        }
    ],

grns key should be array, and update should be of the particular object which matches the key "grnno". Please help me out. Thanks.

==Edit==

var grnno = req.body.grnno;
db.po_grn.find({
    "requirements.grns.grnno":grnno
}).toArray(function(err, po_grn) {
    console.log("po_grn",po_grn);
    if (po_grn.length > 0) {
        console.log("data.grn.grnno ", grnno);
        var query = {
             requirements: {
                $elemMatch: {
                    "grns.grnno": grnno
                }
             }
        };

        var update = {
            $set: {
                'requirements.$[].grns.$[inner].invoice_no': data.invoice_no,
                'requirements.$[].grns.$[inner].vehicle_no': data.vehicle_no,
            }
        };

        var options = {
            arrayFilters: [
                { "inner.grnno" : grnno }
            ] 
        };

        db.po_grn.update(query, update, options
        , function(er, grn) {
            console.log("grn",grn,"er",er)
                        res.send({
                            status: 1,
                            message: "Grn updated successfully"
                        });
                    }
            );
    } else {
            res.send({
                status: 0,
                message: "Grn not found "
            });
    }
})
2
  • Try this $set: { "requirements.$[].grns.$.invoice_no":"test", "requirements.$[].grns.$.vehicle_no":"5455" } Commented Jul 18, 2020 at 7:08
  • @Molda this didn't work well for me, it updated the 0th index, whereas it should have updated the index that matches the key, seems it is for the first index. Commented Jul 18, 2020 at 7:52

1 Answer 1

1

Use a combination of $[] positional-all operator with array filters to update your inner nested document.

var query = {
     requirements: {
        $elemMatch: {
            "grns.grnno": "10431001"
        }
     }
};

var update = {
    $set: {
        'requirements.$[].grns.$[inner].invoice_no': "test",
        'requirements.$[].grns.$[inner].vehicle_no': "5455",
    }
};

var options = {
    arrayFilters: [
        { "inner.grnno" : "10431001" }
    ] 
};

db.collection.update(query, update, options);

Update -

NodeJS native MongoDb driver code attached, which is working fine

enter image description here

const { MongoClient } = require('mongodb');
const url = "mongodb://localhost:27017/";

MongoClient.connect(url, function(err, db) {
  if (err) {
    throw err;
  }

  const dbo = db.db("test");
  (async() => {
    const query = {
        requirements: {
           $elemMatch: {
               "grns.grnno": "10431001"
           }
        }
    };
   
   const update = {
       $set: {
           'requirements.$[].grns.$[inner].invoice_no': "test",
           'requirements.$[].grns.$[inner].vehicle_no': "5455",
       }
    };
   
   const options = {
       arrayFilters: [
           { "inner.grnno" : "10431001" }
       ],
       multi: true
   };

    try {
      const updateResult = await dbo.collection("collection").update(query, update, options);
    } catch (err) {
      console.error(err);
    }
    db.close();
  })(); 
});
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks, this worked in robo 3T, however for some reason I am getting "'No array filter found for identifier \'inner\' in path \'requirements.$[].grns.$[inner].store_grn\'' " this error when i run this in the node.
@pse are you using MongoDb 3.6+ ?
Its: db version v4.0.17
@pse Are you using mongoose or the native mongodb node js driver ?
I upgraded my mongo version to 4.2 and somehow it worked for me
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.