I have the below schema (apologies that it is in coffeescript)
Schema = mongoose.Schema
AuthS = new Schema
auth: {type: String, unique: true}
nick: String
time: Date
Auth = mongoose.model 'Auth', AuthS
I simply want to recover one record which is definitely in my database:
Auth.findOne({nick: 'noname'}, function(obj) { console.log(obj); });
Unfortunately this always logs null. db.auths.findOne({nick: 'noname'}) in mongo shell always returns a value. What is going on?
Found the problem, need to use function(err,obj) instead:
Auth.findOne({nick: 'noname'}, function(err,obj) { console.log(obj); });
Mongoose basically wraps mongodb's api to give you a pseudo relational db api so queries are not going to be exactly like mongodb queries. Mongoose findOne query returns a query object, not a document. You can either use a callback as the solution suggests or as of v4+ findOne returns a thenable so you can use .then or await/async to retrieve the document.
// thenables
Auth.findOne({nick: 'noname'}).then(err, result) {console.log(result)};
Auth.findOne({nick: 'noname'}).then(function (doc) {console.log(doc)});
// To use a full fledge promise you will need to use .exec()
var auth = Auth.findOne({nick: 'noname'}).exec();
auth.then(function (doc) {console.log(doc)});
// async/await
async function async auth() {
const doc = await Auth.findOne({nick: 'noname'}).exec();
return doc;
}
auth();
See the docs if you would like to use a third party promise library.
In my case same error is there , I am using Asyanc / Await functions , for this needs to add AWAIT for findOne
Ex:const foundUser = User.findOne ({ "email" : req.body.email });
above , foundUser always contains Object value in both cases either user found or not because it's returning values before finishing findOne .
const foundUser = await User.findOne ({ "email" : req.body.email });
above , foundUser returns null if user is not there in collection with provided condition . If user found returns user document.
You might want to consider using console.log with the built-in "arguments" object:
console.log(arguments); // would have shown you [0] null, [1] yourResult
This will always output all of your arguments, no matter how many arguments you have.
Use obj[0].nick and you will get desired result,
Related
I have this code that check for me if the token provided is valid or not, the code is working but the problem that it is returning wrong id, => it returns the first Id that he found in the database
the code that I'm using is this
const checkToken = async (req, res ,next) => {
const token= req.body.token //the token is mix of number and letters lenght (6)
User.findOne(token,
(err, user) => {
if (err) {
const error = new Error('Token not Found');
error.status= 406;
return next(err, error);
}else
{
res.send('/api/users/'+ user.id +'/update') // u need to mention user.id from DB
}
})
this is my image of the database :
I don't want to use the id to search the token , what I want is use the provided token and search in DB if it is found so I retrieve Id
According to MongoDB documentation that is the usual behavior of findOne method. When multiple documents satisfy the condition the function returns the first document that is written first. Reference
To check use find() and see all the documents it returns for the correct id and to use findOne make sure the token is unique for all the document.
I have a sever connected to a mongodb database. When I add a first level data and then save that, it works.
For example :
// this works fine
router.post('/user/addsomedata', async (req,res)=>{
try {
const user = await User.findOne({email : req.body.email})
user.username = req.body.username
await user.save()
res.send()
} catch(e) {
res.status(404).send(e)
}
})
BUT if I try to save the object with deeper level data, it's not getting saved. I guess the update is not detected and hence the user didn't get replaced.
Example :
router.post('/user/addtask', auth ,async (req,res)=>{
const task = new Task({
name : req.body.name,
timing : new Date(),
state : false,
})
try {
const day = await req.user.days.find((day)=> day.day == req.body.day)
// day is found with no problem
req.user.days[req.user.days.indexOf(day)].tasks.push(task)
// console.log(req.user) returns exactly the expected results
await req.user.save(function(error,res){
console.log(res)
// console.log(res) returns exactly the expected results with the data filled
// and the tasks array is populated
// but on the database there is nothing
})
res.status(201).send(req.user)
} catch(e) {
res.status(400).send(e)
}
})
So I get the tasks array populated on the console even after the save callback but nothing on the db image showing empty tasks array
You're working on the user from the request, while you should first find the user from the DB like in your first example (User.findOne) and then update and save that model.
Use .lean() with your find queries whenever you are about to update the results returned by mongoose. Mongoose by default return instance objects which are immutable by nature. lean() method with find returns normal js objects which can be modified/updated.
eg. of using lean()
const user = await User.findOne({email : req.body.email}).lean();
You can read more about lean here
Hope this helps :)
here is my code snippet.
I am trying to get details of my friends.friendsList is in reside within the user collection itself and there i am inserting users's id. So first i am fetching userId,then fetching each of their details.but my problem is i am not getting the values of friendsDetails outside the fetchDetailsfunction. I tried many time. i am new to node and sails js. i think its problem of asynchronous execution. How can i solve this problem?
getFriendsDetails:function(req,res){
var userId = req.param('id');
var friendsDetails=[];
User.findOne({
id: userId
}).exec(function(err,user){
var friendsIds=user.friends;
friendsIds.forEach(function(id){
User.findOne({
id: id
}).exec(function fetchDetails(err,Userdetails){
var obj={
id:Userdetails.id,
name:Userdetails.name,
pro_pic:Userdetails.profile_pic
}
friendsDetails.push(obj);
console.log(friendsDetails);//Here consoling pushed data correctly.
});
console.log(friendsDetails);//here i am getting null array
});
});
You can use mongoDB $in clause to get an array of friend documents.
getFriendsDetails:function(req,res){
var userId = req.param('id');
var friendsDetails=[];
User.findOne({
id: userId
}).exec(function(err,user){
var friendsIds = user.friends;
User.find({id : { $in : friendsIds}}).toArray(function(err, data){
console.log(data);
data.forEach(function(friendObj){
var obj={
id: friendObj.id,
name: friendObj.name,
pro_pic: friendObj.profile_pic
}
friendsDetails.push(obj);
});
console.log(friendsDetails);
});
});
}
Your variable is not in the same scope. Therefore, it is null outside the exec function. You are right, it is due to the async nature of javascript.
What you can do is pass a callback to the exec function and pass your variable in.
.exec(function(err, user, callback)
and then call it like this
callback(friendsDetails);
Your second console.log won't wait until your function is finished because it is async.
I'm doing a simple update when my node.js app receives a certain POST request. This is my code:
app.post('/comment', function (req,res) {
var params = req.body;
BlogPost.update({"title": params.title}, {$push: { comments: {author : params.author, content: params.content, date: new Date().toUTCString()}}});
res.redirect('back');
});
where BlogPost is a mongoose Model. (This model works when querying for documents).
Now the problem is, when I do subsequent queries, nothing happens. For example, running the above code for a document with "title" "aaa" (which is supposed to push an object to the array "comments", querying for that document with title "aaa" returns something like
{ _id: 51954d4663aa986aa93a734f,
title: 'aaa',
comments: [] }
Anything I'm doing really wrong?
You should add a callback to get the error message.
I was having a similar issue and simply adding the callback, everything was working fine, even with an empty callback.
Try:
app.post('/comment', function (req,res) {
var params = req.body;
BlogPost.update({"title": params.title}, {$push: { comments: {author : params.author, content: params.content, date: new Date().toUTCString()}}},function(error){console.log(error);});
res.redirect('back');
});
This is such strange behavior by mongoose. I also had this and since update() is deprecated I used updateOne() instead, but it too only works when adding the callback function.
Consider we are searching a document from MongoDB based on the _id value. Which one of the following code is efficient ?
ModelObj.findById(IdValue).exec(callback);
ModelObj.findOne({ '_id': IdValue}).exec(callback);
I feel ModelObj.findById() is efficient, but what are the supportive reasons or How is it efficient?
findById is just a convenience function that does exactly the same thing as the findOne call you show.
Here's the source:
Model.findById = function findById (id, fields, options, callback) {
return this.findOne({ _id: id }, fields, options, callback);
};
findById(id) is almost equivalent to findOne({ _id: id }).
If you want to query by a document's _id, use findById() instead of findOne().
Both functions trigger findOne(), the only difference is how they treat undefined.
If you use findOne(), you'll see that findOne(undefined) and findOne({ _id: undefined }) are equivalent to findOne({}) and return arbitrary documents.
However, mongoose translates findById(undefined) into findOne({ _id: null }).
See https://mongoosejs.com/docs/api.html#model_Model.findById
Here's the source:
Model.findById = function findById(id, projection, options, callback) {
if (typeof id === 'undefined') {
id = null;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return this.findOne({_id: id}, projection, options, callback);
};
findById(id) is just syntactic sugar of the find({_id : id}) or findOne({_id: id})
Using .findOne makes the database look through its records checking each bson document to find the relevant variable and then check the value, if mongo knows its looking for the internally indexed _id field it doesn't have to look through each document