Vinay Sawant
Vinay Sawant

Reputation: 378

Conditionally remove Subdocument nested inside array of document MongoDB

I have a collection with document like this:

{
    "_id" : "ABC",
    "Name" : "Rajesh",
    "createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
    "updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
    "AvgValue" : "65",
    "PreValues" : [ 
        {
            "Date" : 20150709,
            "Rate" : [ 
                {
                    "Time" : 1566,
                    "value" : 60
                }, 
                {
                    "Time" : 1500,
                    "value" : 400
                }, 
                {
                    "Time" : 1400,
                    "value" : 100
                }, 
                {
                    "Time" : 1500,
                    "value" : 103
                }
            ]
        }
    ]
}

I want to remove the duplicate doc for a particular Date value eg If Time value is 1500, I need to pull the document and push it the new value for (Value) in single bulk operation.

Here is my query

bulk.find({ "_id":"ABC" })
    .update(
        { 
            "_id": "ABC",
            "PreValues": { "Date": 20150709 }
        },
       { 
           $pu‌​ll: { "PreValues": { "Rate": { "Time": 1000 } } }
       }
    ); 
bulk.find({ "_id":"ABC" })
    .update(
        { "_id": "ABC","PreValues": { "Date": 20150709 }},
        { $pu‌​sh : { 
            "PreValues": { "Rate": { "Time": 1000,"Rating": 100 }}
        }}
    ); 
bulk.execute();

Upvotes: 1

Views: 895

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50436

It's not a great idea to have nested arrays since the only thing you will ever be able to do atomically is $push or $pull. See the positional $ operator for details on why "nested arrays" are not good here, but basically you can only ever match the position of the "outer" array element.

And that is basically what you are missing here, and of course the proper "dot notation" for accessing the elements:

var bulk = db.ABA.initializeOrderedBulkOp();
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
    .updateOne({ "$pull": { "PreValues.$.Rate": { "Time": 1500 } } })
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
    .updateOne({ "$push": { "PreValues.$.Rate": { "Time": 1500, "Rating": 100 } } })
bulk.execute();

Which alters the document like so:

{
    "_id" : "ABC",
    "Name" : "Rajesh",
    "createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
    "updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
    "AvgValue" : "65",
    "PreValues" : [
            {
                    "Date" : 20150709,
                    "Rate" : [
                            {
                                    "Time" : 1566,
                                    "value" : 60
                            },
                            {
                                    "Time" : 1400,
                                    "value" : 100
                            },
                            {
                                    "Time" : 1500,
                                    "Rating" : 100
                            }
                    ]
            }
    ]
}

That is the correct syntax for both statements there and sends both requests to the server at the same time with a single response.

Note that you need to inclide in the .find() query a field from the outer array to match. This is so the positional $ operator is populated with the matched index of that element and the operator knows which array element to act upon.

Upvotes: 1

Related Questions