Mongoose Static Not Returning Object After Query - mongodb

I want to make a method in my model to return the mongodb id of a user given his twitterid. It looks something like this:
userSchema.statics = {
getMongoIdByTwitterName : function (twittername){
this.findOne(({twitterID : req.user.id},
function(err, user){
};
)
}
}
But this obviously doesnt return anything, how do I make this function return the user?

What about using a callback function?
userSchema.statics = {
getMongoIdByTwitterName : function (twittername, callback){
this.findOne(findOne({twitterID : req.user.id},
callback(err, user);
)
}
}

Related

Order of save() and find() in NodeJS with MongoDB

I'm trying to create a new record in my MongoDB ("thisPlayer") and save it to my database, then find all records in my database (including the new one) and render them.
I am having trouble understanding why my save() function actually occurs after my find() function. When this code executes, the find() function does not include my new thisPlayer record. However, after the find() runs, the save occurs -- the record is saved to the database AFTER the find() ran.
Thanks in advance!
const playerNumber = async function countPlayers() {
return new Promise((resolve, reject) => {
Player.count(function(err, numOfDocs) {
err ? reject(err) : resolve(numOfDocs);
console.log('I have '+numOfDocs+' documents in my collection');
});
});
}
async function playerProfile() {
var count = await playerNumber();
console.log("count already in db: "+ count);
if (count===0) {
teamCaptain=1;
} else {teamCaptain=0};
count++;
const thisPlayer = new Player({
playerNum: count,
playerName: Name,
});
thisPlayer.save();
Player.find({}, function(err, playaz){
var playerOne;
if (playaz.length > 0) {
playerOne = playaz[0].playerName;
} else {
playerOne = "";
}
res.renderPjax("leavetakings",
{player1: "1: " + playerOne}
);
});
}
playerProfile();
You need to use await
for example.
await Player.find({})

.find() returning nothing even when data exists

I've a mongo database with 3 collections for 3 different kind of users as User,Partner,Admin. Whenever a new user of any type signup I'm searching all three collections to check if username and email exist already. I'm trying to achieve this by calling a function as:
function checkAttribute(attr,val,callback){
User.find({attr: val},function(err,user){
if(err){
console.log(err);
}else{
if(user.length === 0){
Partner.find({attr: val},function(err,partner){
if(err){
console.log(err);
}else{
if(partner.length === 0){
Admin.find({attr: val},function(err,admin){
if(err){
console.log(err);
}else{
if(admin.length === 0){
return callback(null,true);
}else{
return callback(null,false);
}
}
});
}else{
return callback(null,false);
}
}
});
}else{
return callback(null,false);
}
}
});
};
Calling function line:
checkAttribute("username",newUser.username,function(error,response){
.......
});
But this is not working as it returns true always even when users with passed username/email exists already. I am unable to find the problem. Any one knows why this is happening?
Thanks in advance.
Since you are passing in the attribute as a variable in the function parameters, the query document
{ attr: val } is an object with the key "attr", not the dynamic attribute you pass in.
To fix this, you need to use computed property names in your query object as
{ [attr]: val }
Also, the function can use async/await pattern to be more readable and for the purpose of finding if a document exist findOne does the job so
well as it returns a document if it exists and null otherwise.
So your function can be refactored as
async function checkAttribute(attr, val, callback) {
try {
const query = { [attr]: val }
const user = await User.findOne(query).exec()
const partner = await Partner.findOne(query).exec()
const admin = await Admin.findOne(query).exec()
const found = (user || partner || admin) ? true: false
return callback(null, found)
} catch (err) {
console.error(err)
return callback(err, null)
}
};
attr: in your queries will search for a db field called attr. If you want to use the function parameter attr, use [attr]: as the key.
Example:
attr = 'username'
User.find({ [attr]: val }, function (err, user) {
if (err) {
console.log(err);
}
})
This is a feature available since ES6 so should work fine. See the docs here for more info

Mongo query always returns the value exists in database, when it does not

I am trying to query for a name field in mongodb and with the following code I always get the response that the value is a duplicate.
var checkUserName = function (userName, email, res){
User.findOne({ name : userName }, function () {
if(userName && typeof userName !== 'undefined'){
res.send("duplicate");
}else{
checkEmail(email);
}
});
}
you are currently ignoring the answer from the database completely and are just checking your input again. This cannot work. Mongoose returns the answer of the query as the second parameter of the callback function (the first is always there to signal errors) - try something like this:
var checkUserName = function (userName, email, res){
User.findOne({ name : userName }, function (err, userFromDb) {
if (err) {
console.log("there was an error: " + err;
return res.send("err: " + err.message);
}
if(userFromDb) {
res.send("duplicate");
} else {
checkEmail(email);
}
});
}

Conditional Mongoose Query

I have a query that I want to run with a where case, only if a variable is false. This is what I'm doing now, but it's not optimal. Is there a way to do this with one query?
if (user) {
models.Interviews.find({}).exec(function (err, interviews) {
// stuff
});
} else {
models.Interviews.find({}).where('group').equals(group_id).where('disabled').equals(false).exec(function (err, interviews) {
// stuff
});
}
If by 'not optimal' you're referring to needing to duplicate the 'stuff' code without a function, you can build up your Query object in steps like this:
var query = models.Interviews.find({});
if (!user) {
query = query.where('group').equals(group_id).where('disabled').equals(false);
}
query.exec(function (err, interviews) {
// stuff
});
Why is this not optimal? How would a single (more complicated) query be better?
What is not so nice is the duplicated "stuff", but you can easily fix that:
var stuff = function(err, interviews) {
// stuff
};
if (user) {
models.Interviews.find({}).exec(stuff);
} else {
models.Interviews.find({})
.where('group').equals(group_id).where('disabled').equals(false)
.exec(stuff);
}
or
var query = models.Interviews.find({});
if (!user){
query = query.where('group').equals(group_id)
.where('disabled').equals(false);
}
query.exec(function(err, interviews) {
// stuff
});

Using $inc to increment a document property with Mongoose

I would like to increment the views count by 1 each time my document is accessed. So far, my code is:
Document
.find({})
.sort('date', -1)
.limit(limit)
.exec();
Where does $inc fit in here?
Never used mongoose but quickly looking over the docs here it seems like this will work for you:
# create query conditions and update variables
var conditions = { },
update = { $inc: { views: 1 }};
# update documents matching condition
Model.update(conditions, update).limit(limit).sort('date', -1).exec();
Cheers and good luck!
I ran into another problem, which is kind of related to $inc.. So I'll post it here as it might help somebody else. I have the following code:
var Schema = require('models/schema.js');
var exports = module.exports = {};
exports.increase = function(id, key, amount, callback){
Schema.findByIdAndUpdate(id, { $inc: { key: amount }}, function(err, data){
//error handling
}
}
from a different module I would call something like
var saver = require('./saver.js');
saver.increase('555f49f1f9e81ecaf14f4748', 'counter', 1, function(err,data){
//error handling
}
However, this would not increase the desired counter. Apparently it is not allowed to directly pass the key into the update object. This has something to do with the syntax for string literals in object field names. The solution was to define the update object like this:
exports.increase = function(id, key, amount, callback){
var update = {};
update['$inc'] = {};
update['$inc'][key] = amount;
Schema.findByIdAndUpdate(id, update, function(err, data){
//error handling
}
}
Works for me (mongoose 5.7)
blogRouter.put("/:id", async (request, response) => {
try {
const updatedBlog = await Blog.findByIdAndUpdate(
request.params.id,
{
$inc: { likes: 1 }
},
{ new: true } //to return the new document
);
response.json(updatedBlog);
} catch (error) {
response.status(400).end();
}
});