2
votes

I am using node js mongodb driver & trying to update an object array inside an object array in a document.

The schema of the document collection is this :

enter image description here

What I Want :

For collection with order no = 1 & items.qty=2 & tax rate = 25, update the tax to "cst" & taxratetype to "flat".

What I Tried :

db.OrderInfo.aggregate(
    {$match:{"orderno":"1"}},
    {$unwind:'$items'},
    { $match: { 'items.qty' : 2} 
 },function(err,result1){
    if(err){
    throw(err);
   }else{
   indexes = result1[0].items.taxes.map(function(obj, index) {
      if(obj.taxrate == 25) {
      return index;
   }
   }).filter(isFinite);

var updateData = {};
updateData["items.$.taxes."+indexes[0]+".tax"]="cst";
updateData["items.$.taxes."+indexes[0]+".taxratetype"]="flat";


db.OrderInfo.update({ "orderno":"1",'items.qty': 2,'items.taxes.taxrate': 25 },{$set: updateData },function(err,result2){
console.log(result2);
});

}
});

Currently I am using db.eval to run this script from node but later will change it once I accomplish the same.

Getting this Error :

{"name":"MongoError","message":"Error: command failed: {\n\t\"ok\" : 0,\n\t\"errmsg\" : \"pipeline element 3 is not an object\",\n\t\"code\" : 15942\n} : aggregate failed :\n_getErrorWithCode@src/mongo/shell/utils.js:25:13\ndoassert@src/mongo/shell/assert.js:13:14\nassert.commandWorked@src/mongo/shell/assert.js:267:5\nDBCollection.prototype.aggregate@src/mongo/shell/collection.js:1312:5\n_funcs1@:1:31\n","ok":0,"errmsg":"Error: command failed: {\n\t\"ok\" : 0,\n\t\"errmsg\" : \"pipeline element 3 is not an object\",\n\t\"code\" : 15942\n} : aggregate failed :\n_getErrorWithCode@src/mongo/shell/utils.js:25:13\ndoassert@src/mongo/shell/assert.js:13:14\nassert.commandWorked@src/mongo/shell/assert.js:267:5\nDBCollection.prototype.aggregate@src/mongo/shell/collection.js:1312:5\n_funcs1@:1:31\n","code":139}

I know from this issue https://jira.mongodb.org/browse/SERVER-831 that I cannot use a direct update command & hence trying this workaround. Any other approach for such updates is also fine with me.

EDIT : As per answer given by @titi23, I had tried using [] also inside function. It did not gave me any error but, my values also did not get updated.

1

1 Answers

2
votes

Two problems in the query :

1) You are missing [] in the aggregate query.

2) The update method does not need the tax rate clause. It will find the nested document & the index from aggregate would serve the purpose in update.

Refer aggregate-definition for more info on how to use it.

Syntax - db.collection.aggregate(pipeline, options)

pipeline - array - A sequence of data aggregation operations or stages.

Try the following:-

db.OrderInfo.aggregate([
{$match:{"orderno":"1"}},
{$unwind:'$items'},
{ $match: { 'items.qty' : 2} }]).toArray(
function(err,result1){
if(err){
    throw(err);
}
else{
   console.log(result[0]); //See is there any record here
   indexes = result1[0].items.taxes.map(function(obj, index) {
  if(obj.taxrate == 25) {
  return index;
  }
 }).filter(isFinite);

var updateData = {};
updateData["items.$.taxes."+indexes[0]+".tax"]="cst";
updateData["items.$.taxes."+indexes[0]+".taxratetype"]="flat";


 db.OrderInfo.update({ "orderno":"1",'items.qty': 2}, /*Remove the tax rate clause from here..*/
      {$set: updateData },function(err,result2){
        console.log(result2);
    });
  }
});

It should not throw the error.

EDIT:- Do toArray() with the aggregate, see if it helps. Updated the query already.