I am having the hardest time finding a solution to something that should be so simple.. I would like to find a document in a mongo database and store it in a variable that i can use anywhere in a node.js app..
The closest I think I have gotten is
var path = db.collection('paths').find().toArray()
where path is a collection holding one document, but then console.log(path[0]) returns undefined..
Try asynchronous way, something like this
var path;
db.collection('paths', function(err, collection) {
collection.find({}).toArray(function(err, results) {
path = results;
console.log(results);
});
});
NOTE
Never try to run IO operation synchronously in node.js because node.js is single threaded. If you do, you would block the whole application. The api provided by mongodb nodejs native is asynchronous, that means the result is expected in some point of time in future but not immediately. As soon as the result is available callback function is called and you get your result.
If you are coming from synchronous coding background, its a paradigm shift. You need to change your mind to think asynchronously.
Probably I'm late answering to this question. I've started working with nodejs and I'm using MongoDB for store all the data and I had the same problem finding a solution to keep the documents in a variable.
As you may know, the queries are async and in that way you can't assign the result in a variable, instead of doing that you have to use a function as a callback and return the value there.
Here's a sample code that I'm using in my project:
var verifyUserExists = function(db, callback, username) {
var collection = db.collection('users');
collection.findOne({ 'login': username }, function(err, doc) {
assert.equal(null, err);
callback(doc);
});
}
mongoClient.connect(mongoUrl, function(err, db) {
assert.equal(null, err);
console.log('Connected successfully to server');
verifyUserExists(db, function(userExists) {
console.log(userExists);
db.close();
}, username);
});
If you want to do other operations with the returned documents you have to do it in the callback, if you try to return the value in the callback function to a global variable you will get undefined because the code is executed async.
Related
I am trying to get all consultation of a patient and if a patient has more than one consultation then i need to iterate through foreach/map, here is my implement of this but this is not working, please help
in below code when i am hitting the api then the response i am receiving is this:
No default engine was specified and no extension was provided
if i am running this code without foreach then it is working and i am getting doc length
router.post('/get/consultations', function(req, res){
console.log("consultation"+req.body.patient_id);
var dc = {};
consultation.find({"patient":req.body.patient_id}).forEach(function(doc){
console.log(doc.length);
//dc.push(doc);
});
res.json(dc);
});
According to Mongoose Doc http://mongoosejs.com/docs/queries.html
When a callback function:
is passed, the operation will be executed immediately with the results passed to the callback.
is not passed, an instance of Query is returned, which provides a special query builder interface.
since your statement
consultation.find({"patient":req.body.patient_id})
didn't pass callback function as an argument. This statement returns a Query object which you can execute by using .exec eg.
// .find returns a Query object
var query = Person.find({ 'name.last': 'Ghost' });
// execute the query at a later time
query.exec(function (err, person) {
if (err) return handleError(err);
console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation) // Space Ghost is a talk show host.
})
so your code should be either one of these way
// using exec
consultation.find({"patient":req.body.patient_id}).exec(function(docs){
docs.forEach(function(doc){
console.log(doc.length);
});
// using callback
consultation.find({"patient":req.body.patient_id}, function(err,docs){
docs.forEach(function(doc){
console.log(doc.length);
});
});
// using promise (mongoose 4+)
consultation.find({"patient":req.body.patient_id}).then( function(docs){
docs.forEach(function(doc){
console.log(doc.length);
});
});
I query one collection (messages) with mongoose. The result is an array of documents. Each document contains an ID for a different collection (users). Now I want to query the users collection for each ID from the messages collection.
The idea is to update each message object with the information from the user collection before returning it to the front end.
I tried using async.each. For some reason the final function is never called even though I am making sure the callback() function is called after each iteration.
app.get('/getmsg', function(req, res){
messages.find({query})
.exec(function(err, ms){
if(err) throw err;
async.each(ms, function(m, callback){
users.findOne({_id : m.userId})
.lean()
.exec(function(err, user){
if(err) {
console.log('error' , err);
callback();
} else {
m.userName = user.name;
// everything is working up to here
callback();
}
}), function(err){
res.send(ms); // this is never returned!
}
});
});
});
Is there a better way of achieving this? I assume this must be a common issue.
Thanks!
You can't use res.send. Instead create a function to get notified about it. Something like this.
// 1st para in async.each() is the array of items
async.each(items,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);
var pg = require('pg');
var conString = "postgres://postgres:abk#localhost/bot";
var res = [];
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client', err);
}
client.query('SELECT * FROM bot.questions', function(err, result)
{
done();
if(err) {
return console.error('error running query', err);
}
res.push(result.rows[0]);
console.log(res); //inside function scope
});
});
console.log(res); // outside function scope
"console.log()" which has called inside the function gives proper resulting array, but outside function the same array variable shows an empty array. I have tried lot of things, such as callbacks, promises functionalities in node js but was not able to see the resulting "res" outside the function.
Please suggest me how do I make that "res" variable accessible from outside of function.
NOTE: Specifically, I need "console.log(res)" to print the "res" outside of function as mentioned in above code.
res variable is indeed accessible outside the function, as it is defined outside the function
res variable is indeed populated outside of the function, as it is seen as populated inside the function
root cause of your problem is that the outside print happens chronologically earlier than the inside activity, as the function is asynchronous, the call comes out immediately, and proceeds to execute the last line in the code.
If you are just particular about getting the value outside, it is indeed is the case
If you are wanting to just print the value outside, use a delayed callback in which to print the content
If you are wanting to post-process the value outside, you will need to link the connect function with a next function, through synchronization primitives.
Hope this helps.
As explained before, the query's result will exist only when the callback is fired, so it won't make sense accessing it in a part of the code that would execute before that.
It seems like you need to read a bit about node's asynchronous programming.
I suggest you read about promises and generators.
I found a solution finally, I have created seperate file for db config along with resulting array of values using callback function to export. Here is the "db.js" file which I have created.
var pg = require('pg');
var conString = "postgres://postgres:abk#localhost/chatbot";
var resp = [];
function executeQuery (callback) {
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client', err);
}
client.query('SELECT * FROM bot.questions', function(err, result) {
done();
if(err) {
return console.error('error running query', err);
}
resp.push(result.rows[0]);
// console.log(res);
callback(resp);
});
});
};
exports.executeQuery = executeQuery;
and this I have imported into my "app.js" like bellow
var express = require('express')
var bodyParser = require('body-parser')
var request = require('request')
var app = express()
var db = require('./db')
app.post('/webhook/', function (req, res) {
db.executeQuery(function ( resp) {
console.log(resp);
});
});
This is how I can now access "resp" as resulting array, and can pass it to any function as an argument wherever required.
There is specific need as per my requirements to make the db config file separate from app.js file, otherwise I know it can also be manipulated in same app.js file.
So finally, This works for me perfectly.
This is what a kind of example I was expecting. But I found it by myself.
Anyways thanks for your involvement, and suggessions.
I need to edit a Game object by adding a User object to it. This is done by the mongoose query findById. This query works. But however, when I want to add the modified game to the resulting array, something goes wrong. The 'console.log(game);' returns the right output, but the 'console.log(result);' is always empty. What is going wrong? Is it something with inner functions?
var result = [];
games.forEach(function(game){
User.findById(game.user1_id, function(err, user){
if(err)
console.log(err);
game.user1 = user;
result.push(game);
console.log(game);
});
});
console.log(result);
You have run into a class callback problem. When you call forEach on games the code will actually continue outside the callback and the result will therefore be the value you first assigned to it, which is []. This is due to the code being evaluated asynchronous.
Solve this by moving your code into a function with a callback that is called when the loop is done, like this:
var utils = require('restberry-utils');
var getResult = function(next) {
var result = [];
utils.forEachAndDone(games, function(game, iter) {
User.findById(game.user1_id, function(err, user) {
if (err) console.log(err);
game.user1 = user;
result.push(game);
iter();
});
}, function() {
next(result);
});
};
getResult(function(result) {
console.log(result);
});
Notice I've imported the restberry-utils package and used the forEachAndDone method. This method will loop through the objects but won't continue unless you call the iter method. When it has looped through all the objects, the last callback is called which is where I'm returning the result.
Hope this makes sense.
I'm trying to retrieve data from my mongolab DB using Node-mongodb-native
var findAll = function () {
var ddocs;
collection.find({}).each(function (arr, docs) {
ddocs = docs;
});
console.log(ddocs);
};
But it seems that when I log ddocs, it will give me undefined, but if I log docs it will show me the data.
Please help
How should I use this function ?
Thanks
Tzelon Machluf
You're basically trying to create a function that will return all of the documents in a collection? If so, the below should do work. However, I agree with #hgoebl and that you should work on your understanding of node as this is not likely the best way to accomplish what you're trying to do.
var ddocs;
var findAll = collection.find().toArray( function(err, docs) {
if(err)
throw err;
console.log('Collection returned');
return ddocs = docs;
});
setTimeout( function(err) {
if(err) throw err;
console.log(ddocs);
db.close();
}, 1000);
One thing in particular to note: collection.find is asynchronous, so the problem in your code (why it says ddocs is undefined) is that you're logging ddocs before the collection.find ever finished; thus, it's initialized, but no assigned any values. The Node convention is to nest callbacks so that everything happens in the right order and when it's ready.