this.find is not a function, Mongoose Schema design - node.js

I'm currently writing a function that will create a notification for every User that is in the committee of a specified Society (It's a social network site btw) and whenever I run this:
User.statics.newSocietyNotification = function(req, socID, typeID, url, next){
var tmpUsers = []
Society.findById(socID, function(err, doc){
console.log(doc)
doc.committee.forEach(function(comMember, i){
tmpUsers.push(comMember._uid)
})
this.find({'_id' : { $in : tmpUsers } }, function(err, docs){
if(err){
console.log(err)
}
if(docs.length == 0 || docs == null){
next(false)
}
next(docs)
console.log(docs)
})
})
}
It crashes the server with this message:
TypeError: this.find is not a function
at /home/ubuntu/workspace/models/user.js:368:10
at Query.<anonymous> (/home/ubuntu/workspace/node_modules/mongoose/lib/model.js:3324:16)
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:259:21
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:127:16
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)
If anyone knows what I'm doing wrong I would greatly appreciate the help :)
EDIT:
Using User.find instead of 'this'
TypeError: User.find is not a function
at /home/ubuntu/workspace/models/user.js:368:10
at Query.<anonymous> (/home/ubuntu/workspace/node_modules/mongoose/lib/model.js:3324:16)
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:259:21
at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:127:16
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)

Your this on line 368 is referring to context of the callback function of the findById method. That callback function (which is an object, under the hood) doesn't have a method called find.
Instead, use Society.find(... or User.find(... to look up something else in the database.

Related

unable to change password using mongoose

I am using MongoDB, mongoose, ejs and NodeJS for my site. I have a update password function which is not working properly. I have checked again and again by login different things in console and there is no problem in getting data in req. So I guess my problem is in the controller. This is my controller:
module.exports.update_password = function (req, res) {
console.log(req.user);
Company.findOne({ username: req.user.username }, function (err, user) {
if (user.password == req.body.current_password) {
if (req.body.new_password == req.body.confirm_password) {
Company.findOneAndUpdate({ username: req.user.username }, { password: req.body.new_password }, { upsert: true }, function (err, doc) {
if (err) return res.send(500, { error: err });
req.flash('notify', 'Password changed!')
return res.redirect('/profile');
});
}
else req.flash('notify', 'New password does not match with confirm password');
}
else req.flash('notify', '!')
});
return res.redirect('/profile');
}
everytime updating my password I get this error:
node:events:355
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:329:5)
at ServerResponse.setHeader (node:_http_outgoing:573:11)
at ServerResponse.header (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:771:10)
at ServerResponse.location (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:888:15)
at ServerResponse.redirect (/home/krush/github/Project_Lightspeed/node_modules/express/lib/response.js:926:18)
at /home/krush/github/Project_Lightspeed/controllers/authentication_controller.js:45:32
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4857:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4857:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4880:21
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/query.js:4397:11
at /home/krush/github/Project_Lightspeed/node_modules/kareem/index.js:136:16
at processTicksAndRejections (node:internal/process/task_queues:76:11)
Emitted 'error' event on Function instance at:
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/model.js:4859:13
at /home/krush/github/Project_Lightspeed/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
[... lines matching original stack trace ...]
at processTicksAndRejections (node:internal/process/task_queues:76:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...
It seems that the problem is that the return res.redirect('/profile'); command is executed before your callback functions. Which is normal since this is how the event loop works.
Try to remove the return res.redirect('/profile'); line to see if the error goes away. Callbacks at node.js execute at a later stage of the event loop.
Generally I would recommend to refactor your code to use promises instead of callbacks since that causes the "callback hell" anti-pattern.
If you refactor your code to use promises, then you will be able to use .then or async await, which will help you write cleaner code and help you spot any error easily.

I get an error when I have 2 entries with similar name

When I have two similar posts with the same title I get this error.
I get the error when I access the page with the same name, having other entries with different names work just fine.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\response.js:170:12)
at done (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\response.js:1004:10)
at tryHandleCache (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\ejs\lib\ejs.js:257:5)
at View.exports.renderFile [as engine] (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\ejs\lib\ejs.js:482:10)
at View.render (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\view.js:135:8)
at tryRender (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\application.js:640:10)
at Function.render (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\application.js:592:3)
at ServerResponse.render (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\express\lib\response.js:1008:7)
at games.forEach.game (D:\DD\documents\100dc\nodejs\gamesplayed\app.js:80:21)
at Array.forEach (<anonymous>)
at Game.find (D:\DD\documents\100dc\nodejs\gamesplayed\app.js:77:15)
at D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\mongoose\lib\model.js:4759:16
at D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\mongoose\lib\query.js:4099:12
at process.nextTick (D:\DD\documents\100dc\nodejs\gamesplayed\node_modules\mongoose\lib\helpers\query\completeMany.js:35:39)
app.post('/newentry', (req, res)=> {
const gameName = req.body.gameName;
const gameImage = req.body.gameImage;
const gamedesc = req.body.gamedesc;
const gameEntry = new Game({title: gameName, description: gamedesc, image: gameImage});
gameEntry.save();
res.redirect('/');
});
app.get('/:title', (req, res) => {
const gameTitle = _.lowerCase(req.params.title);
Game.find((err, games)=> {
games.forEach(game => {
const storedGame = _.lowerCase(game.title);
if (storedGame === gameTitle) {
res.render('post', {title: game.title, image: game.image, desc: game.description, id: game._id })
}
});
});
});
It happens because storedGame === gameTitle becomes true multiple times through the forEach loop. You can not call res.render multiple times during the same request.
Since it looks like you are using mongoose, I would suggest using Game.find to actually find what you are looking for, instead of pulling everything from the database and handling the searching yourself.
Games.find({title: gameTitle}, (err, games) => {
// Return what you want to the client.
})
This will still cause multiple games to be returned, so you need to handle that in some way before responding to the client.
Also look into Promises, as they make the code look much cleaner.
This error occurs when we try to send response more than one time.
const storedGame = _.lowerCase(game.title) will have multiple values and hence after comparing it will be there in the res.render block more than one time so this error will occur.
So comparing should be done in the query itself.
As you have used find, it will return all the games.So, You can try something like this.
Game.find((err, games)=> {
games= games.map(game => {
const storedGame = _.lowerCase(game.title);
if (storedGame === gameTitle) {
return {title: game.title, image: game.image, desc: game.description, id: game._id }
}
});
return res.send(games)
});
Or another way is to use findOne method of ORM to find only one record.

Cannot set headers after they are sent to the client - Node/Mongoose/Express

I am working on an fantasy soccer app for my friends and I, but I am getting this age old error and it doesn't seem like any of the other questions answered on here really fit my situation. In the first block of code below, the console.log is returning the correct data, so I am very certain that the res.json(populatedClub) should be working just fine. I cannot find anywhere else in my code that is triggering another res.send() or res.json() in this chain of events.
Is anybody else able to see what I am not?
My route:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.exec((error, populatedClub) => {
if (error) {
return () => {throw new Error(error)};
}
console.log('populatedClub:', populatedClub);
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);
The error stack:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:471:11)
at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/ubuntu/workspace/node_modules/express/lib/response.js:267:15)
at FantasyClub.findOne.populate.exec (/home/ubuntu/workspace/server/fantasyClub-routes.js:18:11)
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4187:16
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4189:13
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
I figured out what I had done wrong, and it was so simple that I'm almost embarrassed to admit it, but here it goes.
I updated from an older version of Mongoose and forgot to update my code accordingly. Always make sure your code matches what the docs say for the version of the library you are using.
This is the working code:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.then(populatedClub => {
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);

Node.js Mongoose PUT Failed

I am trying to PUT mongoose data using postman but it shows "TypeError: bear.save is not a function" in server console and crash the node app.
In this problem I am running two apps on different ports and db with the same code, normal http app can make all requests(POST,PUT,DEL,GET) success but another https app can't make PUT request, it can only make POST and GET successfully .
I can't understand why the same code on http app not showing error if it was code problem. Please help me.
REST API reference from - Here
.get(function(req, res) {
Bear.find( {ID: req.params.bear_id} , function(err, bear) {
if (err)
res.send(err);
res.jsonp(bear);
});
})
.put(function(req, res) {
Bear.find( {ID: req.params.bear_id}, function(err, bear) {
if (err)
res.send(err);
bear.Name = req.body.Name;
//res.json(bear) can send data up to this line
// save the bear (crash after following line)
bear.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Bear updated!' });
});
})
});
Error Log on console -
TypeError: bear.save is not a function
at Promise.<anonymous> (/var/www/vhosts/mydomain.com/nodeapp.js:130:18)
at Promise.<anonymous> (/var/www/vhosts/mydomain.com/node_modules/mpromise/lib/promise.js:162:8)
at emitOne (events.js:96:13)
at Promise.emit (events.js:188:7)
at Promise.emit (/var/www/vhosts/mydomain.com/node_modules/mpromise/lib/promise.js:79:38)
at Promise.fulfill (/var/www/vhosts/mydomain.com/node_modules/mpromise/lib/promise.js:92:20)
at /var/www/vhosts/mydomain.com/node_modules/mongoose/lib/query.js:1736:26
at model.Document.init (/var/www/vhosts/mydomain.com/node_modules/mongoose/lib/document.js:251:11)
at completeMany (/var/www/vhosts/mydomain.com/node_modules/mongoose/lib/query.js:1734:12)
at cb (/var/www/vhosts/mydomain.com/node_modules/mongoose/lib/query.js:1697:11)
You probably want to use findOne instead of find.

Error using Redis Multi with nodejs

I am using Redis and consulting it from nodejs, using the module Redis.
When i exec a client.multi() and the redis server is down the callback doesn't send the error and the nodejs app terminates.
This is the error
/Users/a/db/node_modules/redis/index.js:151
throw callback_err;
^
TypeError: Cannot read property 'length' of undefined
at Command.callback (/Users/a/db/node_modules/redis/index.js:1098:35)
at RedisClient.flush_and_error (/Users/a/db/node_modules/redis/index.js:148:29)
at RedisClient.on_error (/Users/a/db/node_modules/redis/index.js:184:10)
at Socket.<anonymous> (/Users/a/db/node_modules/redis/index.js:95:14)
at Socket.EventEmitter.emit (events.js:95:17)
at net.js:441:14
at process._tickCallback (node.js:415:13)
this is my code:
Constructor class
var redis = require('redis');
var client;
function Redis(){
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err);
});
}
Redis.prototype.multi = function(commands,callback){
var err = null;
client.multi(commands).exec(function (error, res) {
if(error){
process.nextTick(function(){
callback(error,null)
})
}else{
process.nextTick(function(){
callback(null,res)
})
}
});
}
FYI, I ran across this in an old lib that depended on old version of node_redis.
This issue was a bug and was fixed in v0.9.1 - November 23, 2013: https://github.com/mranney/node_redis/pull/457
I think that people are still reaching here... (not sure if this answers this specific question directly, but I assume people reaching here since the multi.exec() returns true / the event loop is not waiting for it's response.
After the fixes that went in (in node-redis), it is possible to wrap the result of exec with Promise, and then you will be sure that the result will include the replies from the multi.
So, you can add some redis commands to the multi:
await multi.exists(key);
await multi.sadd(key2,member);
And then in the result do something like:
return new Promise((resolve, reject) => {
multi.exec((err, replies) => {
if (err) {
reject(err);
}
return resolve(replies);
});
});
Otherwise, if you will just do: const reply = await multi.exec();
it will just return you true, and not the replies
** Important to mention - this refers to 'async-redis' and 'node-redis'

Resources