Shailesh Shekhawat
Shailesh Shekhawat

Reputation: 235

Filter subdocument and trigger

i have collection of objects inside an invitation, having hard time to filter particular object and trigger it's boolean field.

Document:

"Invitation" : [ 
{
    "__v" : 0,
    "userID" : ObjectId("54afaabd88694dc019d3b628"),//ObjectId of personA
    "__t" : "USER",
    "_id" : ObjectId("54b5022b583973580c706784"),
    "Accepted" : false
}, 
{
    "__v" : 0,
    "userID" : ObjectId("54af6ce091324fd00f97a15f"),//ObjectId of personB
    "__t" : "USER",
    "_id" : ObjectId("54bde39cdd55dd9016271f14"),
    "Accepted" : false
}
]

here i have only two objects inside Invitation array,it can be more than two. Let's say personA and personB send me Invitation, so two different invitation objects are inserted into database having different fields, with objectId of both persons(userID in above document), now if i accept only invitation of personA, it should trigger accepted field of personA object only, here is what i tried so far, but not working as per expectation.

Controller:

User.find({_id: req.user._id},'Invitation',function(err,docs) {
if (err) {
    console.log(err);
}
    var results = [];

    async.each(docs,function(doc,callback) {

        async.each(doc.Invitation,function(invite,callback) {
            User.findOneAndUpdate(
                {'_id': doc._id, 'Invitation._id': invite._id},
                {'$set': {'Invitation.$.Accepted': !invite.Accepted}},
                function(err,doc) {
                    results.push(doc);
                    callback(err);
                }
            );
        },callback);
    },function(err) {
        if (err)
            console.log(err);

        console.log('end'+results);
    });

});

finally i am looking for a query which can be used to filter a single element or object, like if i accept invitation of personA then Accepted field of personA object should be set to true. i would be really helpful if some logic is provided. Thank you

Upvotes: 0

Views: 93

Answers (2)

Neil Lunn
Neil Lunn

Reputation: 151122

Not a very clear question. But it seems all you really need to do here is just match the only sub-document you want to update in the first place:

User.find(
   { 
       "_id": "req.user._id",
       "Invitation._id": personA.id
   },
   { "Invitation.$": 1 },
   function(err,docs) {
     // and continue
   }
);

This is the form of the positional $ operator in a "projection" context. Where only the "singular" matched element is returned.

Once you have a "singular" result, then all the other code works as designed.

I should know after all because I wrote it for you. Not that you are paying any decent respect to that.

Update on Aggregate in Mongodb

Toggle boolean value of subdocuments

Or personA.userID or whatever makes it work.

Just use the unique identifier for the "user" where you expect that to match the query conditions.

Upvotes: 1

Leonardo Delfino
Leonardo Delfino

Reputation: 1498

You can do this:

db.user.update({"invitation.userID": 1}, {"$set" : {"invitation.$.Accepted" : true}});

Replacing the value 1 with the user ID you want to update.

The code is in the syntax of MongoShell, simply convert to driver syntax you are using

The operator used was the $. According to the documentation: The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array. To project, or return, an array element from a read operation, see the $ projection operator.

For more details see: http://docs.mongodb.org/manual/reference/operator/update/positional/

Upvotes: 1

Related Questions