MadPhysicist MadPhysicist - 2 months ago 8
Node.js Question

Mongo Update Record With Values Set In the Same Query

I have the following code for an API that aims to update a document in Mongo. It uses

collection.update
to insert values into a section and then another
collection.update
to push these values into an array within the document.

However, when I run this code, I keep getting
nan
in
events.eventTime
and
events.endDate = null
. How can I modify this to work properly? That is, I first insert values into
runtime.
and subsequently use those to push into
events
array.

router.get('/stop/:id', function(req,res){
var collection = db.get('Activity');

//Important to use findOne here to get an object back instead of an array
collection.findOne({_id : req.params.id }, function(err, activity){
if (err) throw err;
res.json(activity);
//console.log(activity);

collection.update({
_id: activity._id
},
{
$set: {
"runtime.started": false,
"runtime.endDate": new Date()
}
},
function(err, activity){
if (err) throw err;
//res.json(activity);
console.log(activity);
}
);

collection.update({
_id: activity._id
},
{
$push: {events: {
eventTime: ((activity.runtime.endDate - activity.runtime.startDate) / 1000),
startDate: activity.runtime.startDate,
endDate: activity.runtime.endDate
}
},
},
function(err, activity){
if (err) throw err;
//res.json(activity);
console.log(activity);
}
);

});
});


enter image description here

enter image description here

Answer

I guess either you should use promise or nested callback, javascript is asynchronous, so even though it looks like the second update call will be called after first, in reality they are being called at the same time and thus I guess the weird behavior.

It's better to wrap your DB call in promise and apply chaining. maybe you want to look at $q promises which is impressive. If you don't want to use promises, then call the second update method inside the function of the first update call

router.get('/stop/:id', function(req,res){
    var collection = db.get('Activity');

    //Important to use findOne here to get an object back instead of an array
    collection.findOne({_id : req.params.id }, function(err, activity){
        if (err) throw err;
        res.json(activity);
        //console.log(activity);

        collection.update({
            _id: activity._id
        },
        {
            $set: {
                    "runtime.started": false,
                    "runtime.endDate": new Date()
            } 
        },
        function(err, activity){
            if (err) throw err;
            //res.json(activity);
            console.log(activity);
            collection.update({
             _id: activity._id
            },
            {
             $push: {events: {
                        eventTime: ((activity.runtime.endDate - activity.runtime.startDate) / 1000),
                        startDate: activity.runtime.startDate,
                        endDate: activity.runtime.endDate
                    }
                }, 
        },
        function(err, activity){
            if (err) throw err;
            //res.json(activity);
            console.log(activity);
        }
        );
        }
        );

    }); });

Yes looks pretty messy, that's why promises are good.

Update, maybe you can try merging both the update call into one

collection.findOne({_id : req.params.id }, function(err, activity){
        if (err) throw err;
        res.json(activity);
        //console.log(activity);
         var date  = new Date();
         var duration = (date - activity.runtime.startDate)/1000;
        collection.update({
            _id: activity._id
        },
        {
            $set: {
                    "runtime.started": false,
                    "runtime.endDate": date
            },
            $push: {events: {
                        eventTime: duration,
                        startDate: activity.runtime.startDate,
                        endDate: date
                    }
                }
        },
        function(err, activity){
            if (err) throw err;
            //res.json(activity);
            console.log(activity);
    });

});