gopa2000 gopa2000 - 1 month ago 7
JSON Question

Modify nested object with multiple keys without replacing existing keys using Mongoose/NodeJS

Schema and model:

var schema = new mongoose.Schema({
timestamp_hour: Date,
deviceID: Number,
minutes: {
'0': {temperature: Number},
'1': {temperature: Number},
.
.
.
'59': {temperature: Number}
}
},{
collection: 'devices'
});

var model = mongoose.model('deviceData', schema);


Now in a POST request, I receive some data from an external source containing a timestamp, deviceID and temperature value.

My primary key is
timestamp_hour
and
deviceID
, so if there is an existing document in the database, I need to store the temperature value in
minutes: {[minute_value]: temperature}
. I currently derive
minute_value
from the timestamp, and I can query the database, all well and good. Now I need to update the
minutes
object in the document by adding the new key-value pair.

So after deriving the required values, I try running this:

var query = {timestamp_hour: timestamp, deviceID: deviceID};
var update = {minutes: {[minute]: {temperature: tempData}}};

deviceData.findOneAndUpdate(query, update, {upsert: true}, function(err, doc){
if(err) return res.send(500, {error: err});
return res.send("successfully saved");
});


Now the issue is, it replaces the entire
minutes
object inside document with the new single value.

Example:

Original document:

{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "38" : { "temperature" : 39.5 } },
}


Document after update:

{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "39" : { "temperature" : 38.0 } },
}


What I need:

{
"deviceID" : 1,
"timestamp_hour" : ISODate("2016-10-29T08:00:00Z"),
"minutes" : { "38" : { "temperature" : 39.5 }
"39" " { "temperature" : 38.0 } },
}


I'm new to MEAN, but I can see why my approach doesn't work since the update call just modifies the nested object.

I'd appreciate any help regarding the correct approach to use for achieving this functionality.

Answer

You can do this within a single update using a combination of the dot and bracket notations to construct the update object as follows:

var query = { "timestamp_hour": timestamp, "deviceID": deviceID },
    update = { "$set": { } },
    options = { "upsert": true };
update["$set"]["minutes."+ minute] = { "temperature": tempData };

deviceData.findOneAndUpdate(query, update, options, function(err, doc){
    if(err) return res.send(500, {error: err});
    return res.send("successfully saved");
});