Mongoose functions after exec() - javascript

How can run functions like sort and other functions after exec() in mongoose.
I tried to find all documents and populate some fields after that I executed how can I run other functions after I executed in mongoose

Country.find(search).sort(sort).exec((err, result) => {
if (err) return res.send(err);
if (result.length != 0) {
return res.send(result, 'Country list');
} else {
return res.send({}, 'No countries', 400);
}
})
hope this is what your looking for and find it usefull

Related

Using push for inserting JS object into an array wont work at certain context

In the below code, users.push used within ‘db.each’ wont work. However, if I move ‘users.push’ outside then it seems to work.
How can I push the new objects from db.each into the users array?
let db = new sqlite3.Database('./db/main.db', (err) => {
if (err) console.error(err.message);
console.log('Connected to the main database.');
});
var users = [];
db.serialize(() => {
db.each(`SELECT email, name FROM users`, (err, row) => {
if (err) console.error(err.message);
let user = {
email: row.email,
name: row.name
}
users.push(user);
});
});
console.log(JSON.stringify(users));
db.close();
I am using express and sqlite3 node packages.
It's because db.serializeand db.each are asynchronous functions (and return immediately, thus executing console.log before the db callbacks are executed).
Here should be a working example :
db.serialize(() => {
db.each(`SELECT email,
name
FROM users`, (err, row) => {
if (err) {
console.error(err.message);
}
let user = {
email : row.email,
name : row.name
}
users.push(user);
console.log(JSON.stringify(users));
db.close();
});
});
First error: asynchronicity not handled properly
As Antoine Chalifour pointed out, you call console.log(JSON.stringify(users)); before users gets modified in the asynchronous callback. Refer to his answer for fix and explanations.
Second error: errors not handled
You wrote if (err) { console.error(err.message); } then go on with the rest of the function. That is bad, because an error might happen and you'd just continue with your program. You should instead write something like:
if (err) {
console.error(err);
return;
}
or:
if (err) throw err;

Creating error/result function in node

I'm having trouble understanding how to create functions that would return in the format of (err, result) for an Express app.
My current db query function is:
pool.query(
'SELECT id FROM users WHERE email = ? LIMIT 1',
[email],
(results) => { // I'd like this to be (err, results)
if(results instanceof Error){...}
}
})
In my db.js file, pool looks like this:
module.exports = {
query: (query, args, cb) => {
pool.getConnection( (err, connection) => {
if(err){
new Error('No database connections available in pool')
} else {
connection.query(query, args, (error, results, fields) => {
connection.release()
// I got a MySQL error here and I'd like to handle it in my callback function
if(error){
new Error('Bad query')
} else {
cb(results)
}
})
}
})
}
}
For this and other functions, I'd like to return a proper Error if there is one, and have my callback listen for err, result as parameters.
I tried using new Error('Bad query') but that came back as the first variable in my callback no matter what (which is how I ended up with instanceof Error.
How do you structure a callback and response so that your callback can be in the err, result format and check for/handle errors properly on functions you're creating? (I understand how to use it for modules already in this format - I'm talking about writing/formatting your own code.)
Thanks!
You can do it like this:
module.exports = {
query: (query, args, cb) => {
pool.getConnection( (err, connection) => {
if(err){
cb(new Error('No database connections available in pool'));
} else {
connection.query(query, args, (error, results, fields) => {
connection.release();
// I got a MySQL error here and I'd like to handle it in my callback function
if(error){
cb(new Error('Bad query'));
} else {
cb(null, results);
}
});
}
});
}
}
You always pass the error value as the first argument to the callback and, if there is a result, you pass it as the second. Then, within the callback, you check to see if err is non-null and, if so, there is an error. If it's null, then the second argument contains the result.
Note that by not returning or including the actual err value that the database gave you, you may be hiding useful information (like why the query failed).
Then, where you use this, you do something like this:
let query = 'SELECT id FROM users WHERE email = ? LIMIT 1';
pool.query(query, [email], (err, result) => {
if (err) {
// handle error here
} else {
// process result here
}
});

SELECT multiple data from MySQL node.js with promises

The concept of promises is very new for me (so far, I was working with async.each and async.waterfall)
I want to use promises but i'm stuck right now.
I want to get "tags" from my db.
I have two tables for this : One called 'tags' with every tag in it (with an ID) and another one 'user_tags' with every username saved and the ID of the tag that the user (username) created and saved into 'tags'.
I can put information in my DB but now I want to pull this out and log it out (I will display it later)
So far this is my idea :
var getUserprofile = function getUserprofile(username, callback){
pool.getConnection(function (err, connection) {
var dataUser = [];
// Error check
if (err) {
console.log(err);
}
connection.query('SELECT * FROM users_tags FULL JOIN tags ON (tags.id = users_tags.t_id) WHERE users_tags.user_id=666;', username , function (err, rows, fields) {
if (err) {
connection.release();
cb(err);
} else if (rows.length < 1) {
connection.release();
cb("We don't have any informations about this user yet");
} else {
console.log("we pull the information right now");
connection.release();
callback(null, rows[0]);
}
});
});
}
Is this a good idea ? What should I do if I want to use promises for this kind of function ?
Thanks in advance for any help !!!
I would use Bluebird. You can "promisify" existing APIs with Promise.promisify or Promise.promisifyAll.
I would do something like
var Promise = require('bluebird'),
... //other deps;
var pool = Promise.promisifyAll(pool);
function getUserprofile(username){
var connection = null;
return pool.getConnectionAsync()
.then(function (conn) {
connection = Promise.promisifyAll(conn);
return connection.queryAsync('...');
})
.then(function (results) {
if (results.length < 1) {
return "We don't have any informations about this user yet";
} else {
console.log("we pull the information right now");
return results[0];
}
})
.catch(function (err) {
console.log(err);
throw err;
})
.finally(function () {
if (connection) {
connection.release();
}
});
}

Mongoose Find Results and Async

I am writing a NodeJS script that will run every hour through Heroku's scheduler. I am quering the Mongo instance I have (mongohq/compose) and then doing something with those results. I am working with Mongoose.js and the find() command. This returns an array of results. With those results I need to perform additional queries as well as some additional async processing (sending email, etc).
Long story short, due to node's async nature I need to wait until all the processing is complete before I call process.exit(). If I do not the script stops early and the entire result set is not processed.
The problem is that I have a christmas tree effect of calls at this point (5 nested asnyc calls).
Normally I'd solve this with the async.js library but I'm having a problem seeing this through with this many callbacks.
How can I make sure this entire process finishes before exiting the script?
Here's the code that I'm working with (note: also using lodash below as _):
Topic.find({ nextNotificationDate: {$lte: moment().utc()}}, function (err, topics) {
if (err) {
console.error(err);
finish();
} else {
_.forEach(topics, function (topic, callback) {
User.findById(topic.user, function (err, user) {
if (err) {
// TODO: impl logging
console.error(err);
} else {
// Create a new moment object (not moment.js, an actual moment mongoose obj)
var m = new Moment({ name: moment().format("MMM Do YY"), topic: topic});
m.save(function(err) {
if(err) {
// TODO: impl logging
console.error(err);
} else {
// Send an email via postmark
sendReminderTo(topic, user, m._id);
// Update the topic with next notification times.
// .. update some topic fields/etc
topic.save(function (err) {
if(err) {
console.error(err);
} else {
console.log("Topic updated.");
}
})
}
})
}
});
console.log("User: " + topic.user);
});
}
});
Part of what is making your code confusing is the usage of else statements. If you return your errors, you won't need the else statement and save 4 lines of indentation for every callback. That in and of itself will make things drastically more readable.
Using async:
Topic.find({nextNotificationDate: {$lte: moment().utc()}}, function (err, topics) {
if (err) {
console.error(err);
return finish(err);
}
async.each(topics, function(topic, topicCallback) {
async.auto({
user: function (callback) {
User.findById(topic.user, callback);
},
moment: function(callback) {
var m = new Moment({name: moment().format("MMM Do YY"), topic: topic});
m.save(callback);
},
topic: ["moment", "user", function (callback, results) {
var m = results.moment;
var user = results.user;
sendReminderTo(topic, user, m._id);
topic.save(callback);
}]
}, function(err) {
if (err) {
return topicCallback(err);
}
console.log("Topic updated.")
return topicCallback();
});
}, function(err) {
if (err) {
console.error(err);
return finish(err);
}
return finish();
});
});

How do you do a "join" on an array in mongoose (mongodb) with node.js?

How do you do a "join" (i know it is not the correct term) with an array of messages in mongoose?
I tried looping over all the messages and querying to get the user info but it is not working:
messages.forEach(function (message, index) {
User.findById(message.userId, function (err, user) {
messages[index].user = user
})
})
console.log(messages) // the user info is not attatched
So how is this accomplished with mongoose and node.js?
the biggest problem with your code is, that you assume the code to run synchronously - but it doesn't. it runs asynchronously. so messages is not yet set when you execute
console.log(messages);
do something like this instead:
var userIds = [id1, id2, id3];
User.find({"_id": {$in: userIds}}, function (err, users) {
console.log(users);
});
edit
ok, i see. you want to add the userInfo to the different messages.
easiest way to acieve this, is to use the async module: https://github.com/caolan/async
async.map(messages, getUserInfo, function (err, result) {
if (err) {
console.log(err);
return;
}
// log all msg with userinfo
console.log(result);
});
function getUserInfo (msg, callback) {
User.findById(msg.userId, function (err, user) {
if (err) {
callback(err);
return;
}
msg.user = user;
callback(null, msg);
});
}

Categories