Node.js & Mongoose, can't recover _id - javascript

I'm trying to save a document in my collection and if the save is successful, return the _id of this same document. The problem is I get an undefined value to my _id in both case, either the created model from mongoose or from the callback return. Basically, my only way of getting the _id would be to search the document by one of its properties, and then get the value. This approach isnt what I want, knowing what im currently trying to do should work.
var createTrophy = new Trophy({
name : post.name,
accessCode : post.password,
description : post.description,
members : [id]
});
Trophy.findOne({name:post.name}, function(err, trophy) {
if(err){
console.log('Mongoose: Error: ' + err);
res.send('Error db query -> ' + err);
}
else if(trophy){
console.log('Trophy ' + trophy.name + ' already existant');
res.send('Trophy ' + trophy.name + ' already existant');
}else{
createTrophy.save(function(err, doc){
var uid = createTrophy._id;
if (err) {
console.log('Error in trophy saving:' + err);
res.send('Error in trophy saving:' + err);
}else{
User.findOne({_id:post.id}, function(err, user) {
if(err){
console.log('Mongoose: Error: ' + err);
res.send('Error db query -> ' + err);
}
else if(user){
console.log(doc._id + ' ' + uid);
user.trophyLink = doc._id;
res.send(user);
//user.save(function(err){
// if(err){res.send('Couldnt update trophy of profile');}
//});
}
else{
console.log('User id Inexistant');
res.send('User id Inexistant');
}
});
}
});
}
});
});
The Schema
var Trophy = new Schema({
_id : ObjectId,
name : String,
accessCode : String,
description : String,
//reference to User ID
members : [Number],
comments :[Comment]
});

you don't have to supply _id in your Schema, it'll be generated automatically. and if you want the name to be unique you can also configure this in the Schema. if members are supposed to be "real" user _ids, than try sth like [ObjectId].
var TrophySchema = new Schema({
name: {type:String, required:true, unique:true},
accessCode: String,
description: String,
//reference to User ID
members: [ObjectId],
comments: [Comment]
});
and i don't know if this works
var trophy = new Trophy({...data...});
like you did it, i always do it like this:
var trophy = new Trophy();
trophy.name = "my name";
// ...
and the _id should be set as soon as you create the object (http://stackoverflow.com/questions/6074245/node-mongoose-get-last-inserted-id).
so just do it this way:
trophy.save(function (err) {
if (err) {
if (err.toString().indexOf('duplicate key error index') !== -1) {
// check for duplicate name error ...
}
else {
// other errors
}
res.send('Error in trophy saving:' + err);
}
else {
User.findOne({_id:post.id}, function(err2, user) {
if (err2) {/* ... */}
else if (user) {
user.trophyLink = trophy._id;
res.send(user);
}
}
}
});
important is, that save doesn't return the trophy you have to use the one you created yourself.

Related

Cannot Populate Mongodb with new req.body.xxxx data

I am stuck trying to update MongoDB with added req.body.whatever data.
When I get the req.body data to my route, I can see it, change it and update to the database just fine, but when I add say, a new element into the req.body like so:
req.body.newData = "this is new";
In the route, it will not populate into MongoDB with the rest of the existing (changeable) req.body data that already exists in the DB document.
I can in code change an existing req.body.(KeyElement), and updates fine to the DB. Once I try to add an element to req.body, the new one just doesn't get updated. Tried all different update, modify, replaceOne etc and can get an editable result, but still no new elements being added to the database. I even tried the
Model.update(query, {$set: req.body}); etc
and this seems to update as well but nothing new gets added.
Here is the route I'm working with...
router.post('/set-repair-info', ensureAuthenticatedAdmin, function(req, res) {
console.log('set-repair-info : ');
var ObjectId = require('mongodb').ObjectID;
var b = req.body;
console.log('body: ');
console.log(req.body);
var repairToUpdate = req.body.jid;
// console.log(repairToUpdate);
// console.log('req.body[uid]');
// console.log(req.body.jid);
// console.log('userid::: ' + req.body.userid);
// console.log('backuped : ' + req.body.backedup);
// console.log(req.body.username);
//buggy without this;
if (req.body.backedup=='false'){
req.body.backedup == '';
}
//CHECKS AND RESPONSES:
//by Edit
//PARTS ORDERED
if(req.body.repairstatus == 'Parts Ordered'){
req.body.partsordered = 'true'; //THIS WILL NOT GO INTO DB!
} else{
req.body.partsordered = null;
}
req.body.testthisout = "THIS IS A TEST"; //THIS WILL NOT GO INTO DB!
console.log("parts: " + req.body.partsordered);
// Job.replaceOne({ _id: ObjectId(req.body.jid)}, req.body , {upsert: true}, function (err, result) {
// (err === null) ? {msg: 'something happened... err edit user'} : {msg: err}
// });
console.log('body updated: ');
console.log(req.body);
req.body.repairstatus = "Waiting For Something Else"; // UPDATES FINE
Job.update({ _id: ObjectId(req.body.jid)}, { $set: req.body }, function (err, result) {
(err === null) ? {msg: 'something happened... err edit user'} : {msg: err}
});
req.flash('success_msg','Repair has successfully been edited and saved to the database.');
res.render('edit-repair', { job: {'data': req.body} });
});
Double check your Models Schema and make sure variable is setup there.
Check your routes that create an instance of the Schema, make sure value is in there. And .save() or update through mongoose method.
SAVE the file.

Storing questions to an array of data

I've been trying to figure out how to add comments to an array of data in my local db. The idea I'm working on now is to add the array of comments to the array of data so it's easy to know which comment is for which set of data. When I try to do so using the following code, it won't work:
(This is in the userschema where I define the array that will hold the data)
test1: { type: array, required: false }
(Next I try to add the comment array with push but it won't work, I'm using test 0 as an example normally it will depend on what test you'd like to add your comments to. Test1 consists in turn of more arrays with the data in question to which I want to add the comments. Which is why I use user.test1[0])
user.test1[0].push(newComment);
(That does not work while the following does using splice)
user.test1.splice(1, 0, newComment)
For some reason it seems like a can't access the user.test1[0] but I have no idea why? Or should I use another technique when it comes to adding comments to a test?
app.updateTest1 = function(newComment1, newComment2, index) {
app.errorMsg = false; // Clear any error message
app.disabled = true; // Lock form while processing
// Check if username submitted is valid
var userObject = {}; // Create the user object to pass to function
userObject._id = app.currentUser; // Pass current user _id in order to edit
userObject.test1 = [$scope.newComment1, $scope.newComment2];
User.editUser(userObject).then(function(data) {
});
};
userFactory.editUser = function(id) {
return $http.put('/api/edit', id);
};
router.put('/edit', function(req, res) {
var editUser = req.body._id; // Assign _id from user to be editted to a variable
if (req.body.name) var newName = req.body.name; // Check if a change to name was requested
if (req.body.username) var newUsername = req.body.username; // Check if a change to username was requested
if (req.body.email) var newEmail = req.body.email; // Check if a change to e-mail was requested
if (req.body.permission) var newPermission = req.body.permission; // Check if a change to permission was requested
if (req.body.test1) {
var newTest1 = req.body.test1;
}
if (req.body.test2) {
var firstTest2 = req.body.test2;
var newTest2 = firstTest2.split(" ");
}
if (req.body.test3) {
var firstTest3 = req.body.test3;
var newTest3 = firstTest3.split(" ");
}
if (req.body.test4) {
var firstTest4 = req.body.test4;
var newTest4 = firstTest4.split(" ");
}
if (req.body.test5) {
var firstTest5 = req.body.test5;
var newTest5 = firstTest5.split(" ");
}
// Look for logged in user in database to check if have appropriate access
User.findOne({ username: req.decoded.username }, function(err, mainUser) {
if (err) {
// Create an e-mail object that contains the error. Set to automatically send it to myself for troubleshooting.
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: 'gugui3z24#gmail.com',
subject: 'Error Logged',
text: 'The following error has been reported in the MEAN Stack Application: ' + err,
html: 'The following error has been reported in the MEAN Stack Application:<br><br>' + err
};
// Function to send e-mail to myself
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if logged in user is found in database
if (!mainUser) {
res.json({ success: false, message: "no user found" }); // Return error
} else {
// Check if a change to name was requested
if (newName) {
// Check if person making changes has appropriate access
if (mainUser.permission === 'admin' || mainUser.permission === 'moderator') {
// Look for user in database
User.findOne({ _id: editUser }, function(err, user) {
if (err) {
// Create an e-mail object that contains the error. Set to automatically send it to myself for troubleshooting.
var email = {
from: 'MEAN Stack Staff, cruiserweights#zoho.com',
to: 'gugui3z24#gmail.com',
subject: 'Error Logged',
text: 'The following error has been reported in the MEAN Stack Application: ' + err,
html: 'The following error has been reported in the MEAN Stack Application:<br><br>' + err
};
// Function to send e-mail to myself
client.sendMail(email, function(err, info) {
if (err) {
console.log(err); // If error with sending e-mail, log to console/terminal
} else {
console.log(info); // Log success message to console if sent
console.log(user.email); // Display e-mail that it was sent to
}
});
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if user is in database
if (!user) {
res.json({ success: false, message: 'No user found' }); // Return error
} else {
user.name = newName; // Assign new name to user in database
// Save changes
user.save(function(err) {
if (err) {
console.log(err); // Log any errors to the console
} else {
res.json({ success: true, message: 'Name has been updated!' }); // Return success message
}
});
}
}
});
} else {
res.json({ success: false, message: 'Insufficient Permissions' }); // Return error
}
}
if (newTest1) {
// Check if person making changes has appropriate access
if (mainUser.permission === 'admin') {
// Look for user in database
User.findOne({ _id: editUser }, function(err, user) {
if (err) {
res.json({ success: false, message: 'Something went wrong. This error has been logged and will be addressed by our staff. We apologize for this inconvenience!' });
} else {
// Check if user is in database
if (!user) {
res.json({ success: false, message: 'No user found' }); // Return error
} else {
-> (this is where i think the problem is) if (Array.isArray(newTest1)) {
var index = newTest1[2];
-> this doesn't work user.test1[0].push(newTest1);
//user.test1.splice(index, 0, newTest1)
} else {
var testet1 = newTest1.split(" ");
user.test1.push(testet1); // Assign new name to user in database
}
// Save changes
user.save(function(err) {
if (err) {
console.log(err); // Log any errors to the console
} else {
res.json({ success: true, message: 'Name has been updated!' }); // Return success message
}
});
}
}
});
} else {
res.json({ success: false, message: 'Insufficient Permissions' }); // Return error
}
}
You need to make sure user.test1[0] value exists before manipulating it. So if your user.test1
var user = {};
user.test = [];
var arrayToPush = [1,2,3];
try {
user.test[0].push(arrayToPush)
} catch (err) {
document.getElementById('out').innerHTML += err
}
var user2 ={}
user2.test=[];
try {
user2.test.push(arrayToPush)
user2.test.push(arrayToPush)
} catch (err) {
document.getElementById('out2').innerHTML += err
}
document.getElementById('out2').innerHTML += user2.test[0]
<div id="out"></div>
<br>
<div id="out2"></div>
array has no values at all you can't push to it anything.

save() callback not being invoked on a mongoose schema object

Im trying to save a json object in my database. The save() function is not being called but and the json object is never saved.
Help me figure out the problem.
I guess it's a connection problem with mongoose.
Here is my code..
var config = require('../config');
var user = require('../user');
api.post('/addUser',function(req,res) {
var userID;
//creating a sample user under Model collection User.. so this becomes a document!!
console.log("addition of new user api hit!!");
//sending a query to retrieve the no of users served
MongoClient.connect(dbURL, function (err, db) {
var UserCountCursor = db.collection("ourusers").find({"docName": "userCount"}).limit(1);
UserCountCursor.each(function (err, doc) {
if (err)
console.log("did not get the count");
else
// var countString= JSON.stringify(doc);
//var docJson=JSON.parse(countString);
console.log("the json content is:" + doc.iparkoUserCount);
//increase the user count by 1 in the db.
var incCount = parseInt(doc.iparkoUserCount) + 1;
console.log("no of userrs:" + incCount);
// making an userId
userID = "ipkoID_C" + incCount.toString();
//updating using MOngoClient
db.collection("ourusers").update({"docName": "userCount"}, {$set: {"iparkoUserCount": incCount}});
console.log("the user count in the db has been updated!!");
console.log("generated id for this guy is:" + userID);
if (userID != null) {
console.log("calling the save function");
//closing the mongoclient connection
db.close();
signUpUser(userID);
}
});
});
function signUpUser(userIDD) {
var me = new user({
name: req.body.new_name,
password: req.body.new_pswd,
username: req.body.new_username,
phno: req.body.new_phn,
userId: userIDD
});
console.log("the obj ::" + JSON.stringify(me));
console.log("obj created and ready to be stored");
//connecting to the db using mongoose
mongoose.connect(config.database, function (err) {
if (err)
console.log("The error is :"+err);
else {
console.log("WE ARE CONNECTED USING MONGOOSE");
//saving the sample user document
me.save(function (err) {
console.log("in the save func");
if (err) throw err;
else {
console.log('User saved Successfully!!!!!');
res.json({
'whatStatus': 'user saved in the database!!',
'userID': userIDD
});
mongoose.connection.close();
}
});
}
});
}
});
My console logs::
addition of new user api hit!!
the json content is:143
no of userrs:144
the user count in the db has been updated!!
generated id for this guy is:ipkoID_C144
calling the save function
the obj ::{"name":"Abhi","password":"jio","username":"abhijio","phno":"45142545","userId":"ipkoID_C144","_id":"583295bfa0f9f8342035d3b9"}
obj created and ready to be stored
C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\utils.js:98
process.nextTick(function() { throw err; });
^
TypeError: Cannot read property 'iparkoUserCount' of null
at C:\Users\shivendra\WebstormProjects\iParko\routes\RegisteredParkingLots.js:76:57
at handleCallback (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\utils.js:96:12)
at C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:742:16
at handleCallback (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\utils.js:96:12)
at C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:676:5
at handleCallback (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\node_modules\mongodb-core\lib\cursor.js:156:5)
at setCursorDeadAndNotified (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\node_modules\mongodb-core\lib\cursor.js:496:3)
at nextFunction (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\node_modules\mongodb-core\lib\cursor.js:588:12)
at Cursor.next [as _next] (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\node_modules\mongodb-core\lib\cursor.js:681:3)
at nextObject (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:673:8)
at Cursor.next (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:262:12)
at _each (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:738:10)
at C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:746:7
at handleCallback (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\utils.js:96:12)
at C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\lib\cursor.js:676:5
at handleCallback (C:\Users\shivendra\WebstormProjects\iParko\node_modules\mongodb\node_modules\mongodb-core\lib\cursor.js:156:5)
Process finished with exit code 1
You seem to be opening the db connection twice one with mongoose.connect and another one with mongoose.connection.open(). That's why you are getting error.
Try using this with just one connection as below.
mongoose.connect(config.database, function(err, db) {
//var dbcon=mongoose.connection.open();
//dbcon.on('error',function(){console.log('connction error:')});
//dbcon.once('open',function(){
if(err) {
console.log(err);
} else {
console.log("WE ARE CONNECTED USING MONGOOSE");
//saving the sample user document
me.save(function (err) {
console.log("in the save func");
if (err) throw err;
else {
console.log('User saved Successfully!!!!!');
res.json({
'whatStatus': 'user saved in the database!!',
'userID': userIDD
});
//mongoose.connection.close();
}
});
}
});
Inside your UserCountCursor.each(...) loop, after checking for err you should also check for doc. So where you have this:
UserCountCursor.each(function (err, doc) {
if (err)
console.log("did not get the count");
else
// var countString= JSON.stringify(doc);
//...
})
do this instead:
UserCountCursor.each(function (err, doc) {
if (err){
console.log("did not get the count");
}else if(doc){
// var countString= JSON.stringify(doc);
//...
}
})
Then you will avoid the Cannot read property 'iparkoUserCount' of null error and you'll get into your save() function.

Mongo $addToSet with multiple values correct syntax

I have this mongoose schema:
var listingSchema = new Schema({
street : String,
buildingNumber : Number,
apartmentNumber : Number,
UsersAndQuestions: [{
userID: String,
questionID: [String]
}]
});
And I just want to update it with a new entry to UsersAndQuestions which will consist of a userID which is a String, and a questionID which is also a String (but needs to be inserted into an array).
I am using this PUT request:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid')
So I have all the necessary parameters in hand.
Usually, when I wanted to update a field in a schema I used this code that I wrote:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addReportedUser/:userid/:listingid', function (req, res) {
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {reportedUsersIDs: ObjectId(idToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the reportedUserID to the listing" + err);
}
else {
console.log("Success adding reportedUserID to listing!");
}
})
});
You can see I used $addToSet and it worked well. But now I want to add two parameters to a field which is an array. I thought about doing something like this:
app.put('/api/listing/:street/:buildingNumber/:apartmentNumber/addUserInput/:userid/:listingid/:questionid', function(req,res){
var listingToUpdate = req.params.listingid;
var idToAdd = req.params.userid;
var questionToAdd = req.params.questionid;
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions.userID : ObjectId(idToAdd), UsersAndQuestions.questionID : ObjectId(questionToAdd)}}
, function (err) {
if (err) {
res.send("There was a problem adding the user and question to the listing" + err);
}
else{
console.log("Success adding user and question to the listing!");
}
})
});
But I'm obviously getting a SyntaxError.
What is the correct syntax for doing what I tried to do?
Thanks a lot! :)
You need to add object to set UsersAndQuestions:
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }}
UPDATE.
I would do it with two queries:
Listing.update({_id: ObjectId(listingToUpdate), 'UsersAndQuestions.userID': idToAdd},
{"$addToSet": {"UsersAndQuestions.$.questionID": questionToAdd}}
, function (err, result) {
if(result.n === 0){
//we haven't found document with the userId - idToAdd
//we need to insert to UsersAndQuestions document with this user
Listing.update({_id: ObjectId(listingToUpdate)},
{$addToSet: {UsersAndQuestions: { userID: idToAdd, questionID: questionToAdd } }},
function(err, res){
})
}
})

Node.js callback with node_redis

I'm still trying to get into node.js and probably getting some things not quite right. What I'm looking foward to accomplish is to query first a hmap containing a list of rooms. This list is going to be iterated trough to get for each room further details like room name etc.
Here's what the query should return:
redis 127.0.0.1:6379> lrange rooms 0 -1
1) "room:5000"
and
redis 127.0.0.1:6379> hgetall room:5000
1) "name"
2) "room1"
3) "admin"
4) "user:1001"
5) "public"
6) "true"
here's my function within the routes.index
exports.index = function(req, res){
var render_rooms = new Array();
req.app.settings.redis.lrange('rooms',0,-1, function(error, rooms) {
if (error) {
console.log('Error: '+ error);
}
else {
rooms.forEach(function(room){
console.log("room: " + room);
req.app.settings.redis.hgetall(room, function(error, roomdetails){
if (error) {
console.log('Error: '+ error);
}
else {
console.log("roomdetails: " + roomdetails.public);
if(roomdetails.public == "true"){
render_rooms.push(roomdetails.name);
}
}
});
});
// console.log('Name: ' + result);
// res.render('account', { title: 'account title', user: req.user.username, votes: result });
}
});
console.log("length: " + render_rooms.length);
res.render('index', { title: 'Index', username: req.user.username, rooms: render_rooms });
};
I'm not sure if I'm using node_redis properly to achieve this. Further I came up with the idea to store all room details in an array which I'm looking forward to send to the view. Apparently the list always display no elements as I guess is called before the list is filled as I'm missing some essential callback functionality. Howeever I'm not able to fiddle it in. Can someone explain me in some more detail how it "should" work?
Your basic problem is that you need to wait to render the render_rooms array until all the asynchronous processing has completed. The way it is written now, res.render is being called before any of the async Redis queries have completed.
Something like this:
exports.index = function(req, res){
var render_rooms = new Array();
req.app.settings.redis.lrange('rooms',0,-1, function(error, rooms) {
// Keep track of the number of rooms we have left to process.
var roomcount = rooms.length;
if (error) {
console.log('Error: '+ error);
}
else {
rooms.forEach(function(room){
console.log("room: " + room);
req.app.settings.redis.hgetall(room, function(error, roomdetails){
if (error) {
console.log('Error: '+ error);
}
else {
console.log("roomdetails: " + roomdetails.public);
if(roomdetails.public == "true"){
render_rooms.push(roomdetails.name);
}
// Render code moves to here and is only run after all rooms
// have been processed.
if (--roomcount === 0) {
console.log("length: " + render_rooms.length);
res.render('index', {
title: 'Index',
username: req.user.username,
rooms: render_rooms
});
}
}
});
});
}
});
};
Once you get comfortable with what this is doing, take a look at cleaning it up a bit by using async.forEach or async.forEachSeries which more cleanly support this type of flow.

Categories