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

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.

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");
});

Okay, so this works:
deviceData.findOne(query, function(err, doc) {
if(err) return done(err);
if(!doc){
data.save(function(err){
if(err) throw err;
res.json({"Result":"Success"});
});
} else {
doc.minutes[minute] = {temperature: tempData}
doc.save(function(err) {});
res.json(doc);
}
});

Related

RowDataPacket returns empty object but it is not empty [React/Next]

I've been stressing around trying to fix this and I've burnt myself out. I'm calling my serverless mysql trying to get kanbans from teams. I've used this method multiple times and all were working fine but that is most likely because of they only return single item whilst this returns multiple items.
This is my code which returns empty object.
async function getKanbans(team_id){
let kanbans = [];
await sql_query(`SELECT id, sName FROM table WHERE iTeam = ?`, [team_id])
.then(result => {
result.forEach(kanban => {
// console.log(kanban);
kanbans.push({
id: kanban.id,
name: kanban.sName
});
});
})
.catch(err => {
console.log(err);
});
console.log(kanbans);
return kanbans;
}
As you can see.. I am trying to print kanbans and I do get:
[
{ id: 1, name: 'Kanban_1' },
{ id: 2, name: 'Kanban_2' }
]
of out it. Then I'm trying to return it to the item that called this function and this is how that looks like:
teams.push({
id : team.id,
sName : team.sName,
sColor : team.sColor,
aKanbans : result[0]['selectedTeam'] == team.id ? getKanbans(team.id) : null,
});
(a small snippet of something bigger)
Okay, so now when I try and look at the data response (from the frontend) I get this:
{
"success": true,
"message": "Found teams",
"teams": [
{
"id": 1,
"sName": "Team1",
"sColor": "#fcba03",
"aKanbans": {}
},
{
"id": 2,
"sName": "Team2",
"sColor": "#2200ff",
"aKanbans": null
}
]
}
aKanbans from Team1 is empty, empty object. What the **** do I do? I tried mapping it and still got an empty object. React/javascript is not my main language, I just like to learn. Any suggestions?
You are mixing async / await function with normal Promises handling.
Try to change your getKanbans code like this:
async function getKanbans(team_id) {
let kanbans = [];
try {
const result = await sql_query(
`SELECT id, sName FROM table WHERE iTeam = ?`,
[team_id]
);
result.forEach((kanban) => {
kanbans.push({
id: kanban.id,
name: kanban.sName,
});
});
} catch (err) {
console.log(err);
}
return kanbans;
}
And then populate the teams using (declare the parent async):
teams.push({
id : team.id,
sName : team.sName,
sColor : team.sColor,
aKanbans : result[0]['selectedTeam'] == team.id ? getKanbans(team.id) : null,
});

How to get an json object in JsonArray using Mongoose

I am trying to update a json object in an array using the following code. The code seems to be finding the json object in the array, however, it fails to update the json object inside the json array. It doesn't give any error so that's what makes it more confusing.
function addOrUpdateAppointment(jsonObject, isDatabaseOperationSuccessful) {
var docID = jsonObject.doctorID; // this is _id from db sent to the doctor upon logging in
console.log("jsonPssed: ", {_id : docID});
DoctorModel.findOne({_id : docID, 'appointmentList.patientID': jsonObject.appointment.patientID}, {'appointmentList.$.patientID': jsonObject.appointment.patientID},function(err, foundData) {
console.log("found data", foundData);
if(err) {
console.error("error in find doctor for adding the appointment", err);
isDatabaseOperationSuccessful(false, foundData);
return;
}
else {
// since no document matched your query, add the appointment
if (!foundData) {
DoctorModel.update(
{_id: docID},
{$push: {appointmentList: jsonObject.appointment}},
function(err, pushedData) {
if(err) {
console.error("error in adding", err);
isDatabaseOperationSuccessful(false, pushedData);
}
else {
console.log("adding successful", pushedData, "inserted: ", jsonObject.appointment);
isDatabaseOperationSuccessful(true, pushedData);
}
}
);
}
// since that appointment already exists, update it
else {
foundData.update({'_id':docID,'doctors.appointmentList.patientID' : jsonObject.appointment.patientID}, {$set: {'doctors.appointmentList.$.dateAndTime': jsonObject.appointment.dateAndTime}},
function(err, updatedData) {
if (err) {
console.error("error in updating", err);
isDatabaseOperationSuccessful(false, foundData);
}
else {
if (!updatedData) {
console.log("updating failed", updatedData);
isDatabaseOperationSuccessful(true, foundData);
}
else {
console.log("updating successful", updatedData);
isDatabaseOperationSuccessful(true, foundData);
}
}
}
);
}
}
});
}
Schema:
doctorSchema = mongoose.Schema({
name : String,
appointmentList : Array // array of jsonObjects of dates and time
});
Data that I am passing to addOrUpdateAppointment(),
{
"docID": "id assigned by mongoDB",
"appointment": {
"patientID": "id assigned by mongoDB",
"dataAndTime": "IIII"
}
}
Your code is almost correct just change foundData with DoctorModel when you want to update the data. So the code becomes:
else {
DoctorModel.update({'_id':docID, 'appointmentList.patientID' : jsonObject.appointment.patientID}, {$set: {'appointmentList.$': jsonObject.appointment}},
function(err, updatedData) {....});

Unable to Insert Data into a collection

I have officer Schema in which if a user wants to fix an appointment, his entry is made in the DB. The schema is:
officerSchema = mongoose.Schema({
email : {type: String,
index: { unique: true }
},
appointmentList : Array // array of jsonObject of dates and userID
});
The AppointmentList is an array of JSON Objects which contains the ID of the officer with which appointment has to be made, date and userID (the user which wants to fix the appointment).
However to avoid duplicate appointment entries, I have been using several methods mentioned on the internet. None of them have worked for me so far. I am posting the code below. The problem with below code is it NEVER inserts any data in the appointmentsList. However if I use save() instead of update() insertion occurs but duplicates also get inserted.
Here is the JSON Object that I want to add in the array from DB,
{
"id": "1321231231",
"appointment": {
"userID": "31321",
"date": "24 March"
}
}
var ID = requestObject.id;
var newObject = {$addToSet: requestObject.appointment};
OfficerModel.findOne({_id : ID}, function(err, foundData) {
if(err) {
console.log(err);
return;
}
else {
var dbList = foundData.list;
dbList.push(newObject);
foundData.update(function(err, updatedData) {
if(err) {
console.log( err);
}
else {
console.log("successful");
}
});
}
});
Using the $addToSet operator might work for you.
var appt = {
id: "1321231231",
appointment: {
userID: "31321",
date: "24 March"
}
}
Officer.update(
{_id: ID},
{$addToSet: {appointmentList: appt}},
function(err) { ... }
);
But it's not a perfect solution because {one: 1, two: 2} and {two: 2, one: 1} aren't interpreted as equal, so they could both get added to an array with $addToSet.
To totally avoid duplicates, you could do something like this:
var appt = {
id: "1321231231",
appointment: {
userID: "31321",
date: "24 March"
}
};
Officer.findOne(
{_id: ID, 'appointmentList.id': appt.id},
function(err, officerDoc) {
if (err) { ... }
// since no document matched your query, add the appointment
if (!officerDoc) {
Officer.update(
{_id: ID},
{$push: {appointmentList: appt}},
function(err) { ... }
);
}
// since that appointment already exists, update it
else {
Officer.update(
{_id: ID, 'appointmentList.id': appt.id},
{$set: {'appointmentList.$.appointment': appt.appointment}},
function(err) { ... }
);
}
}
);
The operation above that updates the existing appointment uses the positional operator.

Parsing doubly nested JSON object to MongoDB

Schema for my MongoDB model:
var resultsSchema = new mongoose.Schema({
start_date: String,
end_date: String,
matches:[{
id:Number,
match_date:String,
status:String,
timer:Number,
time:String,
hometeam_id:Number,
hometeam_name:String,
hometeam_score:Number,
awayteam_id:Number,
awayteam_name:String,
awayteam_score:Number,
ht_score:String,
ft_score:String,
et_score:String,
match_events:[{
id:Number,
type:String,
minute:Number,
team:String,
player_name:String,
player_id:Number,
result:String
}]
}]
});
Example of JSON data coming from the server:
"matches":
[
{
"match_id":"1234"
"match_date":"Aug 30"
...
...
"match_events":
[
{
"event_id":"234",
"event_minute":"38",
...,
...
},
{
"event_id":"2334",
"event_minute":"40",
...,
...
}
],
{
"match_id":"454222"
"match_date":"Aug 3"
...
...
"match_events":
[
{
"event_id":"234",
"event_minute":"38",
...,
...
},
....
My current implementation works for parsing just the matches (i.e the first array). But I can't seem to access the inner array properly.
async.waterfall([
function(callback) {
request.get('http://football-api.com/api/?Action=fixtures&APIKey=' + apiKey + '&comp_id=' + compId +
'&&from_date=' + lastWeek_string + '&&to_date=' + today_string, function(error, response, body) {
if (error) return next(error);
var parsedJSON = JSON.parse(body);
var matches = parsedJSON.matches;
var events = parsedJSON.matches.match_events;
var results = new Results({
start_date: lastWeek_string,
end_date: today_string,
matches:[]
});
_.each(matches, function(match) {
results.matches.push({
id: match.match_id,
match_date: match.match_formatted_date,
status:match.match_status,
timer:match.match_timer,
hometeam_id:match.match_localteam_id,
hometeam_name:match.match_localteam_name,
hometeam_score:match.match_localteam_score,
awayteam_id:match.match_visitorteam_id,
awayteam_name:match.match_visitorteam_name,
awayteam_score:match.match_visitorteam_score,
ht_score:match.match_ht_score,
ft_score:match.match_ft_score,
et_score:match.match_et_score,
match_events:[]
});
});
_.each(events, function(event) {
results.matches.match_events.push({
id:event.event_id,
type:event.event_type,
minute:event.event_minute,
team:event.event_team,
player_name:event.event_player,
player_id:event.event_player_id,
result:event.event_result
});
});
I understand that the second _.each loop should be iterating for every match, since very match has it's own events subarray. I'm just not sure how to structure this and have been struggling with it for a while.
I tried nesting that loop inside the _.each(matches, function(match) { loop but that didn't work.
Thank you.
Edit: How could I get this to work?
var results = new Results({
start_date: lastWeek_string,
end_date: today_string,
matches:[
match_events: []
]
});
Because then as #zangw says I could construct the match_events array first, append it to matches, and so on.

How do you insert an array of object into Mongodb node.js

Basically i want to insert into my Mongodb collection called "Events" an array of objects called "Events" with an id for each entry into the array.
This is the result i want to get in json:
{
"events" : [
{
"_id" : ObjectId("53a99cc608ad49712a830081"),
"eTitle" : "Freshers Fair",
"eDesc" : "Bring some friends with you oh wait, you have non ha !",
"eDate" : "2014-06-19 11:20",
"eLink" : "http://fair.com",
"eEvent" : "NEFS"
},
{
"_id" : ObjectId("53a99cc608ad49712a830082"),
"eTitle" : "Blahh",
"eDesc" : "Blah fdinidf !",
"eDate" : "2014-06-19 11:20",
"eLink" : "http://google.com",
"eEvent" : "NEFS"
}
]
}
So far this is the result i have:
[
{
"_id":"53a9b5ed745363432d823d7a",
"eTitle":"jrnfdeiujn rd",
"eDesc":"grfdsreds",
"eDate":"2014-07-05 22:33",
"eLink":"reser",
"eEvent":"Victoria Center"
},
{
"_id":"53a9b771745363432d823d7b",
"eTitle":"Hello worlds",
"eDesc":"blah",
"eDate":"2014-07-20 22:33",
"eLink":"http://google.com",
"eEvent":"social"
}
]
This is how i insert data with node.js:
// Set our collection
var collection = db.get('Events');
// Submit to the DB
collection.insert({
"eTitle" : eTitle,
"eDesc" : eDesc,
"eDate" : eDate,
"eLink" : eLink,
"eEvent" : eEvent
}, function (err, doc) {
if (err) {
// If it failed, return error
res.send("There was a problem adding the information to the database.");
}
else {
// If it worked, set the header so the address bar doesn't still say /adduser
res.location("eventlist");
// And forward to success page
res.redirect("eventlist");
}
});
So please i how do i make the format look this the first json format i provided. sorry for the nooby question, just started learning node ! Thanks alot
UPDATE
To post Events:
router.get('/eventlist', function(req, res) {
var db = req.db;
var collection = db.get('Events');
collection.find({},{},function(e,docs){
console.log(docs);
res.send(docs);
// res.render('eventlist', {docs: JSON.stringify(docs), title: 'Test'});
});
});
You can do this:
collection.find({},{},function(e,docs){
var doc = { Events : docs };
console.log(doc);
res.send(doc);
// res.render('eventlist', {docs: JSON.stringify(docs), title: 'Test'});
});