I am using Express.js for my app and mongodb for database (also mongodb Nativ driver).
I created a model with two functions, for getting posts and comments:
// Get single Post
exports.posts = function(id,callback){
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
var collection = db.collection('posts');
collection.find({psotId:id}).limit(1).toArray(function (err, result) {
if (err) {
return callback(new Error("An error has occured"));
} else {
callback(null,result);
}
db.close();
});
}
});
}
// Get post comments
exports.comments = function(id,callback){
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
var collection = db.collection('comments');
collection.find({postId:id}).toArray(function (err, result) {
if (err) {
return callback(new Error("An error has occured"));
}
else {
callback(null,result);
}
db.close();
});
}
});
}
and I created a route to show single post:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
post.comments(post[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:post,comments:comments})
}
})
}
})
})
When I run this code I get this error:
TypeError: Object [object Object] has no method 'comments'
When I use this two function separately its work fine:
I mean like this :
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
res.render('blogPost',{post:post})
}
})
})
//Get post comments
router.get('/post/1',function(req,res, next){
post.comments(1,function(err,comments){
if(err){
console.log(err)
}else{
res.render('blogPost',{comments:comments})
}
})
})
But when I use post.comments as callback for post.posts I get an error.
I wants know why this happening? After some research I couldn't find a solution and I an getting confused.
In your source code you have the following:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
post.comments(post[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:post,comments:comments})
}
})
}
})
})
when you are calling post.posts you have a callback and there you have a return value which you called post (which it is the same variable name of var post = require('../models/post');
Basically change it in the callback like this:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,posts){ //HERE changed post into posts
if(err){
console.log(err)
}else{
post.comments(posts[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:posts,comments:comments})
}
})
}
})
})
EDIT: for better understanding I would change var post = require('../models/post'); into var postModel = require('../models/post'); SO it is much more understandable
EDIT 2: since he posted the real version code
Basically you have the same problem, line 37 of route.js is overriding the movie variable.
You have to call the variable that comes back form the callback with another name, for example movieslike you used to do in the other 2 above.
router.get('/m/:movieId',function(req,res, next){
var id = parseInt(req.params.movieId);
movie.get(id,function(err,movies){
if(err){
console.log(err)
}else{
movie.subtitles(movies[0].imdb,function(err,subs){
if(err){
console.log(err)
}
else{
res.render('moviePage',{movie:movies,subtitles:subs})
}
})
}
})
})
If you copy-pasted this from your source then its because you mispelled the method.
post.commencts
should be
post.comments
Related
Im trying to keep a record from all my errors in a WebService I'm making in node-js;
I've written the following code to keep track of a mysql query possible error:
var err_db = [];
try{
if(error.length == 0){
...
var con = mysql.createConnection({
host: "my_host",
user: "my_user",
password: "my_pass",
database: "my_db"
});
con.connect(function(err) {
if (err) err_db[err_db.length] = err.message;
con.query("IM TRYING HARD TO GET AN SQL ERROR", function (err) {
if (err) err_db[err_db.length] = err.message;
console.log(err_db); //FIRST LOG SHOWS CORRECT
});
console.log(err_db); // THE ERROR DISAPEARS FROM ARRAY
});
}
}
catch(err){
if(err) err_db[err_db.length] = err.message;
}
The problem is the error only keeps stored in array inside the con.query function, after that it disappear, and I want to keep it in a array because later on I intend in sending this possible errors as a JSON to through the WebService response. Thanks in advance.
This is a normal asynchronous nature of node.js. Since the query is executed in a slight greater time so next line is executed first.
try{
if(error.length == 0){
...
var con = mysql.createConnection({
host: "my_host",
user: "my_user",
password: "my_pass",
database: "my_db"
});
con.connect(function(err) {
if (err) err_db[err_db.length] = err.message;
con.query("IM TRYING HARD TO GET AN SQL ERROR", function (err) {
if (err) err_db[err_db.length] = err.message;
console.log(err_db); //FIRST LOG SHOWS CORRECT
// throw the error from here
});
console.log(err_db); // THIS EXECUTED EARLIER THAN THE PREVIOUS
});
}
}
catch(err){
if(err) err_db[err_db.length] = err.message;
}
Asynchronous code cannot catch exceptions using try-catch.
You can try the following code.
var EventEmitter = require('events');
var emitter = new EventEmitter();
var err_db = [];
var con = mysql.createConnection({
host: "my_host",
user: "my_user",
password: "my_pass",
database: "my_db"
});
if (error.length == 0) {
con.connect(function (err) {
if (err) {
emitter.emit('err_db', err);
return;
}
con.query("IM TRYING HARD TO GET AN SQL ERROR", function (err) {
// if (err) err_db[err_db.length] = err.message;
// console.log(err_db); //FIRST LOG SHOWS CORRECT
if (err) {
emitter.emit('err_db', err);
return;
}
});
console.log(err_db); // THE ERROR DISAPEARS FROM ARRAY
});
}
emitter.on('err_db', (err) => {
// handle db err...
err_db[err_db.length] = err.message
});
I'm actually creating a chat like Discord with servers and channels using Node.JS, MongoDB and Mongoose.
Actually, my structure is this one:
https://github.com/copostic/My-Simple-Chat/tree/master/models
But to get the conversations, I have to make so much nested functions and I would like to know if there was a better way to organize my code..
Here's the code with the nested functions, I'm trying to get the message list of each channel of each server:
"use strict"
const Server = require('../models/server'),
Channel = require('../models/channel'),
Message = require('../models/message'),
User = require('../models/user');
exports.getChannels = function (req, res, next) {
// Only return one message from each conversation to display as snippet
Server.find({members: req.session._id})
.select('_id')
.exec(function (err, servers) {
if (err) {
res.send({ error: err });
return next(err);
}
servers.forEach(function (server) {
Channel.find({ serverId: server })
.exec(function (err, channels) {
// Set up empty array to hold conversations + most recent message
let fullConversations = [];
channels.forEach(function (channel) {
Message.find({
'channelId': channel._id
})
.sort('creationDate')
.limit(1)
.populate({
path: "author",
select: "profile.firstName profile.lastName"
});
.exec(function (err, message) {
if (err) {
res.send({
error: err
});
return next(err);
}
fullConversations.push(message);
if (fullConversations.length === conversations.length) {
return res.status(200).json({
conversations: fullConversations
});
}
});
});
});
});
});
};
Thanks a lot
I wanna take the whole list of notifies from mongo db but it returns empty([]) array also I know that i need callback or shorter way of it . Do you have any idea for collecting any data from mongodb by node.js? If I call this /Notifies method (http://127.0.0.1:5000/Notifies)
var MongoClient = require('mongodb').MongoClient;
var express = require("express");
var app = express();
format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/Test', function (err, db) {
if (err) {
throw err;
} else {
console.log("successfully connected to the database");
}
db.close();
});
app.get('/Notifies', function (req, res) {
// BAD! Creates a new connection pool for every request
console.log('connected');
MongoClient.connect('mongodb://127.0.0.1:27017/Test', function (err, db) {
if (err) throw err;
var coll = db.collection('Notifies');
var arr = [];
coll.find({}, function (err, docs) {
docs.each(function (err, doc) {
if (doc) {
console.log(doc);
arr.push(doc);
} else {
res.end();
}
});
});
return res.json(arr);
});
});
var port = Number(process.env.PORT || 5000);
app.listen(port, function () {
console.log("Listening on " + port);
})
Don't use for docs.each instead of this use .toArray so it will return directly a array and then use Json.stringify to convert it into json string array
MongoClient.connect('mongodb://127.0.0.1:27017/Test', function (err, db) {
if (err) throw err;
var coll = db.collection('Notifies');
coll.find({}).toArray(function (err, result) {
if (err) {
res.send(err);
} else {
res.send(JSON.stringify(result));
}
})
});
The problem is you are returning the empty array from within the function, before the actual DB operation occurs. You need to move the line return res.json(arr);
into the find function:
app.get('/Notifies', function (req, res) {
// BAD! Creates a new connection pool for every request
console.log('connected');
MongoClient.connect('mongodb://127.0.0.1:27017/Test', function (err, db) {
if (err) throw err;
var coll = db.collection('Notifies');
var arr = [];
coll.find({}, function (err, docs) {
console.log(docs);
docs.each(function (err, doc) {
if (doc) {
console.log(doc);
arr.push(doc);
} else {
res.end();
}
});
return res.json(arr);
});
});
});
Also, for future use, do not reuse variable names in nested functions (you have 3 functions that use the variable err).
I'm developing a simple rest API in Node.js, and it works middling.
This is my controller code:
...
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err){
callback({error: 'Not Found'});
}
else{
callback(courses);
}
});
}
And this is my route:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(resp){
res.status(200).json(resp);
});
});
This code works and show results of my collection in mongodb.
But the code below, doesn't show results with postman:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(err, resp){
if(err){
res.status(404).send(err);
}
else{
res.status(200).json(resp);
}
});
});
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err)
return callback(new Error('Not Found')); // You must return Error by standard
callback(null, courses); // You must set first argument (error) to null
});
}
...
// You can check that id is number
app.get('/courses/:id(\\d+)', function(req, res, next) {
var id = req.params.id;
courseController.listById(id, function(err, resp) {
if(err)
return next(err); // Pass error to error-handler (see link below)
res.status(200).json(resp);
});
Best practice for callback function is first argument as error and second as result.You should
exports.listById = function (id, callback) {
Course.findById(id, function (err, courses) {
if (err) {
callback(error);
}
else {
callback(null, courses);
}
});
}
while your route should look like this:
app.get('/courses/:id', function (req, res) {
var id = req.params.id;
courseController.listById(id, function (error, courses) {
if (error) return res.status(500) // internal server error
// if I remember correctly, sources is empty array if course not found
res.status(200).json(resp);
});
});
I'm quite new to both javascript and Node/Express, and it's probably a newbie question, but here goes...
I'm building a Rest API, and want to throw new Error(err.message) from this function:
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
callback(err);
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(recordset[0]);
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
... so I can do this in my Express API route:
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
try {
db.hentQuiz(1, function(result) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
}
catch (error) {
res.status(404).send(error)
}
});
I can't get my head around how to do this... Anyone that can help? :)
In node, there is a convention that the first parameter of a callback should be the potential error.
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
return callback(err); //notice the return statement
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(null, recordset[0]); //notice I send null for the error
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
(I'm not sure how you get form db.hentQuiz to hentForfatter.)
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
db.hentQuiz(1, function(err, result) {
if(err) return res.status(404).send(error);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
});
Try using two parameters if using callbacks:
callback(err, result)
And then check for
err and result.
In addition look up how promise chains work.