add new properties to object with variable name in mongoose - node.js

I need to store responses to questions in Mongo. I am using Mongoose. My query looks like this right now:
router.post('/answers', expressJwt({secret: config.secret}), function (req, res, next) {
var user = req.user
var question = req.body.question
var answer = req.body.answers
var id = question._id
db.User.update({email: user.email}, {$set: {answers[question._id]: answer}}, function (err, doc) {
if (err) {
console.error('problem updating answers object', err)
return res.json(err)
}
console.log(doc)
return res.json('successfully updated answers')
})
})
I get an error 'unexpected token [' How can I add properties to my answers object?
I had to make a db call to get the answers object, then modify it, then update it back to the db. Here is the code I used. Note: use lean and exec with mongoose to get raw object otherwise you will run into problems modifying mongoose objects.
router.post('/answers', expressJwt({secret: config.secret}), function (req, res, next) {
var user = req.user
var question = req.body.question
var answer = req.body.answers
var id = question._id
db.User.findOne({email: user.email}).lean().exec(function (err, user) {
user.answers[question._id] = answer
db.User.update({email: user.email}, {$set: {answers: user.answers}}, function (err, doc) {
if (err) {
console.error('problem updating answers object', err)
return res.json(err)
}
console.log(doc)
return res.json('successfully updated answers')
})
})
})

First,you have to set id in your answer object before database call,then replace your field with your new field
router.post('/answers', expressJwt({secret: config.secret}), function (req, res, next) {
var user = req.user
var question = req.body.question
var answer = req.body.answers
answer.question._id = question._id;
db.User.update({email: user.email}, {$set: {answers: answer}}, function (err, doc) {
if (err) {
console.error('problem updating answers object', err)
return res.json(err)
}
console.log(doc)
return res.json('successfully updated answers')
})
})

Store it in a variable instead of using the literal object syntax:
var $set = {};
$set[answers[question._id]] = answer;
db.User.update({email: user.email}, {$set: $set}, function (err, doc) {
// ...
Also, if you have ES6 features available to you (e.g. a recent version of io.js) you can use the special bracket notation in object literals to achieve the same thing:
db.User.update({email: user.email}, {$set: {[answers[question._id]]: answer}}, function (err, doc) {
// ...

Related

mongoose findOne work using id instead of _id

I was stuck for a while when I do _id in findOne function I got empty result.
exports.getUser = function(req, res) {
User.findOne({id: req.params.id}, function(err, user) {
if (err) {
return res.status(400).send({
msg: err
})
} else {
return res.json({status:1, data: user})
}
})
}
Above code worked but I'm curious why this won't work
...
User.findOne({_id: req.params.id}, function(err, user) {
...
I think I have to parse req.params.id with ObjectId function, but is there any global method that ignore this rule? for me it make sense just use _id: myId

GET request for specific id returning null

I'm attempting to build a simple CRUD application using express and mongodb. My GET request for all database entries is working and my POST request is working but I can't seem to figure out the problem with my GET request for individual entries.
Server.js GET request:
app.get('/api/:id', function (req, res) {
var id = req.params.id;
db.collection('api').findOne({_id: id}, (err, result) => {
if (err){
res.sendStatus(404);
return console.log(err);
}
res.redirect('/');
return console.log(result);
});
});
When I type 'url/api/593555074696601afa192d7f' which is an ID I know exists the console.log is returning null, I'm not sure if I'm doing something wrong?
You should pass ObjectID instance in the query.
let ObjectID = require("mongodb").ObjectID;
app.get('/api/:id', function (req, res) {
var id = req.params.id;
db.collection('api').findOne({_id: ObjectID(id)}, (err, result) => {
if (err){
res.sendStatus(404);
return console.log(err);
}
res.redirect('/');
return console.log(result);
});
});
Give Mongoose a try. It might be of help if your models get complex.

Mongoosedb: query by username

Problem Question: I am using MongooseDB with Nodejs and I have user schema
var UserSchema = new mongoose.Schema({
userEmail: String
});
how would I query using the userEmail?
I tried following but no result. On my postman i get cast to ObjectId failed error
router.get('/:userEmail', function(req, res, next) {
User.find(req.params.userEmail, function (err, userDetails) {
if(err){
return next(err);
}res.json(userDetails);
})
});
You need to create a query object or document that has the userEmail property and a value from the req.params object. In your case, this would be:
router.get('/:userEmail', function(req, res, next) {
User.find({ "userEmail": req.params.userEmail }, function(err, userDetails) {
if(err){
return next(err);
}
res.json(userDetails);
});
});
Please try this syntax
router.get('/:userEmail', function(req, res, next) {
User.find({"userEmail":req.params.userEmail}, function (err, userDetails) {
if(err){
return next(err);
}res.json(userDetails);
})
});
You have to put condition on which field you want to query data.
I am unable to reproduce your error "ObjectId failed error". However, I am adding another answer to give you more options.
The following things are slightly different from other answers:-
1) "lean()" is used to ensure that you will be returned a plain JavaScript object
2) Excluded the "_id" from JSON response though I am not sure whether you need the "Id" in the response. This is just to check whether "id" in response is causing the problem.
router.get('/:userEmail', function(req, res, next) {
User.find({"userEmail": req.params.userEmail}, {"_id":false}).lean().exec(function(err, users) {
if (err) {
return next(err);
}
console.log(users);
res.json(users);
});
});

NodeJS array push is not working [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 years ago.
I am doing very simple requests to take some data from MongoDB and then send them to my views
router.get('/', isAuthenticated, function(req, res) {
Conversation.findAllConversation(req.user._id, function(err, data) {
if (err) return console.error(err); // handle this
var array = [];
data.forEach(function (element, index, array){
ConversationReply.findLastReply(element._id, function(err, replys) {
if(err) return cosole.log(err);
console.log(replys);
array.push(replys);
});
});
console.log(array);
res.render('messages/index', {
title : 'Messages',
conversations: data,
user: req.user,
lastReplys: array });
});
});
But all data from replys is not pushing to my array and then just sending empty. Console.log(replys) showing me all my replys correctly.
findLastReply is returning asynchronously, while the request function is proceeding synchronously. To fix this, I would do something like this:
router.get('/', isAuthenticated, function(req, res) {
Conversation.findAllConversation(req.user._id, function(err, data) {
if (err) return console.error(err); // handle this
var array = [];
data.forEach(function (element, index, array){
ConversationReply.findLastReply(element._id, function(err, replys) {
if(err) return cosole.log(err);
console.log(replys);
array.push(replys);
if (array.length === data.length) {
// we are done! :D
console.log(array);
res.render('messages/index', {
title : 'Messages',
conversations: data,
user: req.user,
lastReplys: array });
}
});
});
});
});
Even better is to use Promises, but this is not required.

NodeJS / Mongoose Filter JSON

I am building a JSON API with ExpressJS, NodeJS and Mongoose:
Input -> id:
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}, function (err, product) {
if (!err) {
console.log(product);
return res.send(product);
} else {
return console.log(err);
}
});
});
It shows well the JSON:
[{"_id":"B443U433","date":"2014-08-12","reference":"azerty","file":"087601.png","
....:.
{"_id":"HGF6789","date":"2013-09-11","reference":"azerty","file":"5678.pnf","
...
I just want to display the _id in the JSON, so it is good when I have lots of data.
How I can do that? Something like a filter?
You can chain calls to select and lean to retrieve just the fields you want from the docs you're querying:
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}).select('_id').lean().exec(
function (err, product) {
if (!err) {
console.log(product);
return res.send(product);
} else {
return console.log(err);
}
});
});
You would have to iterate over your "products" object to obtain the ids
Something like this:
(Disclaimer: I haven't tested this)
app.get('/folder/:id', function (req, res){
return Cars.find({reference: req.params.id}, function (err, product) {
if (!err) {
console.log(product);
var ids = new Array();
for(var i = 0; i < product.length; i++){
ids.push(product[i]._id);
}
return res.send(JSON.stringify(ids));
} else {
return console.log(err);
}
});
});
--Edit
Also, "products" may already be a JSON string. You may want to parse it before looping.
product = JSON.parse(product);
Other answers are true but I think it's better to limit data in mongoose like this :(it's same as mongo shell commands)
app.get('/folder/:id', function (req, res){
Cars.find({reference: req.params.id} ,{ _id : true } ,function (err, product) {
if (!err) {
console.log(product);
} else {
console.log(err);
}
});
});

Resources