nodejs mongodb cursor problems - node.js

I have this function that I want to return the value of a mongo query but I am getting undefined values. I am attempting to read the Email address of all of the users in the users collection of my test database.
This is my code:
var mongo = require('mongodb').MongoClient;
var connectionString = "mongodb://cannotdivulge.info.com:53778/testdb";
var users;
var db = mongo.connect(connectionString, function(err, db) {
if(err)
throw err;
console.log("connected to database");
users = db.collection('users');
});
exports.findAll = function(req, res) {
var cursor = users.find();
var result;
cursor.each(function(err, doc) {
if(err)
throw err;
result = doc.Email;
});
res.send(result);
};
result should be equal to the email address but it's undefined. The value of doc.Email is not being preserved. When I place res.send() inside cursor.each(), it will return a value.
Also, I will need to use the result variable in the function before actually returning it's value. That is why I need it's value to be preserved.

Your findall function is async. You'll need to return the results only after completing the list. In your code, the function was returning the value of result before the first callback for each had started.
exports.findAll = function(req, res) {
var cursor = users.find();
var result = [];
cursor.each(function(err, doc) {
if(err)
throw err;
if (doc === null) {
// doc is null when the last document has been processed
res.send(result);
return;
}
// do something with each doc, like push Email into a results array
result.push(doc.Email);
});
};

Related

why the function does'nt return value as expected?

1.I have a function that establish db connection and returns the connection object or the db handle.It is passed as an argument to other functions that use CRUD functions.Code is written in Node js file.
wrote two function one for db connection initiate and other to use the object returned by it
// function to return the db handle
function getDbConnection()
{
var dc;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
return db;
});
}
// function to insert data
function CreatePost(dbo)
{
console.log(typeof dbo);
var mydbo = dbo.db("fb");
for(var i=0;i<25;i++)
{
postData = { pstID: ""+i, pstTitle: "Highway 37",pstTime: "100",pstdBy: "100",pstCntnt: "100"};
mydbo.collection("mypost").insertOne(postData, function(err, res) {
if (err) throw err;
console.log("1 document inserted");
dbo.close();
});
}
}
var dbo = getDbConnection();
CreatePost(dbo);
Error shown while executing
var mydbo = dbo.db("fb");
TypeError: Cannot read property 'db' of undefined

Write and read in Mongo collection with asynchronous node.js implementation

I'm beginner in nodeJS and I have some problems to manage asynchronous way of thinking.
I try to save data in my MongoDB Database and retrieve it. I get my data from a websocket service each 1 ms to 5 sec.
When it's each 5 sec there is no problem but each 1ms, when I display my collection content, the data are not already saved.
Here is my code :
// --Websocket event coming every 1 ms--//
while (1) { //Simulate Websocket events coming every 1 ms
dataBookSave(dataArrayfunction, function(log) { //array of data received from websocket event
console.log(log); //Display the callback log from the function dataBookSave
var query = ""; // Empty query in MongoDB to retrieve all data
mongoDb.find(dbName, collectionName, query, function(result) { // get all data from the MongoDB collection.
console.log(results); //Display all data from my MongoDB collection
});
}
}
function dataBookSave(dataArray, callback) {
if (dataArray.length < 1) callback("dataBookSave1"); //test if the array is empty. if yes, generate the callback
for (var i = 0; i < dataArray.length; i++) {
(function(i) { //closure the for loop
var objAdd = JSON.parse('{"data" : ' + dataArray[i] + ' }'); // create the object to add in the collection
mongoDb.insertCollection(dbName, collectionName, objAdd, function() { // insert function in MongoDB
if (i == dataArray.length - 1) // test if the loop is finished.
{
callback("dataBookSave2"); // if yes, generate the callback
}
});
})(i);
}
}
function insertCollection(dbName, collectionName, myObj, callback) {
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/" + dbName;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbase = db.db(dbName);
dbase.collection(collectionName).insertOne(myObj, function(err, res) {
if (err) throw err;
db.close();
callback();
});
});
}
function find(dbName, collectionName, query, callback) {
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/" + dbName;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbase = db.db(dbName);
dbase.collection(collectionName).find(query).sort({
_id: -1
}).toArray(function(err, result) {
if (err) throw err;
callback(result);
db.close();
});
});
}
I see when the for loop is executed, the asynchronous process iterate each data of the table and don't wait the insert database function to be executed. When the for loop is done, I read the collection in MongoDB. The problem is that data is still in queue, going to be written in the collection.
How can I resolve that? Give up with the async concept? Use closure? Find a best callback implementation?
You definitely don't want to connect/close the connection to your db every 1ms. Keeping the connection open is in this case recommended.
I haven't run the code bellow but it should work
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/" + dbName;
var mongodb;
var collectionName = "some-collection";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
mongodb = db;
run();
});
function run() {
// --Websocket event coming every 1 ms--//
while (1) { //Simulate Websocket events coming every 1 ms
dataBookSave(dataArrayfunction, function(log) { //array of data received from websocket event
console.log(log); //Display the callback log from the function dataBookSave
find(collectionName, function(result) { // get all datas from the MongoDB collection.
console.log(results); //Display all datas from my MongoDB collection
});
});
}
}
function dataBookSave(dataArray, callback) {
if (dataArray.length < 1) callback("dataBookSave1");
var arr = [];
// push object to arr for bulk insertion
for (var i = 0; i < dataArray.length; i++) {
arr.push({
data: dataArray[i]
});
}
insert(collectionName, arr, function() {
callback("dataBookSave2");
});
}
function insert(col, arr, callback) {
mongodb
.collection(col)
.insertMany(arr, function(err, res) {
if (err) throw err;
callback();
});
}
function find(collectionName, query, callback) {
mongodb
.collection(collectionName)
.find(query)
.sort({ _id: -1 })
.toArray(function(err, result) {
if (err) throw err;
callback(result);
});
}

How to return value from asynchronous function in node.js

I have recently started learning MEAN. I have the following code to return collection of document of MongoDb.
var giveData = function()
{
var mongodb = require('mongodb');
var mongoClient = mongodb.MongoClient;
var url = 'mongodb://127.0.0.1:27017/ngs'
var retVal; // this is a return value which will contain documents
mongoClient.connect(url, function(err, db)
{
if (err)
{
console.log(err)
}else
{
db.collection('employees').find().toArray(
function(err, doc)
{
if(err)
{
throw err;
}else{
console.log(doc); // this works fine
retVal = doc; // this does not assign the value ???? why so ??
}
}
);
}
}
)
console.log("Message from lib");
console.log(retVal); // this returns undefined
console.log("-----------------");
return retVal; // this may return data from the server but is returning undefined
}
module.exports ={ showMessage: showMessage,
giveData: giveData
}
From the remarks it is clear that I want collection of documents from MongoDb database into a variable called retVal, which I have assigned value of doc on correct process.
Although the document is displayed successfully but somehow it does not get assigned to variable called retVal.
Please throw some light on the subject so that collection of document is returned from the function called giveData()
Thanks and regards.
In this section
var retVal; // this is a return value which will contain documents
retVal is undefined
And at the bottom
return retVal; // this may return data from the server but is returning undefined
retVal is still undefined because the call to mongoClient.connect is asynchronous
You're returning the value of retVal at a specific moment. This value will not change.
You should pass a callback function to giveData so you can access the returned data once it is received.
var giveData = function(callback) {
var mongodb = require('mongodb');
var mongoClient = mongodb.MongoClient;
var url = 'mongodb://127.0.0.1:27017/ngs'
mongoClient.connect(url, function(err, db) {
if (err) {
callback(err)
} else {
db.collection('employees').find().toArray(function(err, doc) {
if(err) {
callback(err)
} else {
callback(null, doc)
}
})
}
}
}
module.exports = {
showMessage: showMessage,
giveData: giveData
}
And than use it like so
giveData(function(err, doc) {
if(err) {
// handle error
} else {
// you can now use doc!
}
})
You need to get more familiar with asynchronous flow of the Node.js - this may help, for example .
Your bottom console.log and return happens before your assignment (retVal = doc;)
All the functions of mongoClient are asynchronous, and the returning should happen right after assignment (which happens after collection employees is fetched).
the code proceed to your current return without waiting the data from db.collection('employees').
All code could be refactored to use node.js callback. Sure there are much mure elegant ways to solve it, but just to show you example.
var retVal;
function getEmployees(cb) {
return mongoClient.connect(url, function(err, db) {
if (err) return cb(err);
db.collection('employees').find().toArray(
function(err, doc){
if(err) return cb(err);
console.log(doc);
cb(null,doc);
});
});
}
getEmployees((err, result) => {
if (err) console.log('Error:',err);
retVal = result;
return retVal;
});

TypeError: Cannot read property 'findOne' of undefined

Here are the codes
var mongo = require('mongodb');
var databaseName = 'Starter',
collectionName = 'wines';
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
db = new Db(databaseName, server);
db.open(function(err, db) {
if(!err) {
console.log("Connected to 'winedb' database");
db.collection(collectionName, {strict:true}, function(err, collection) {
if (err) {
console.log("The 'wines' collection doesn't exist. Creating it with sample data...");
populateDB();
}
});
}
});
exports.findById = function(req, res) {
var id = req.params.id;
console.log('Retrieving wine: ' + id);
db.collection(collectionName, function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
These codes are based on a sample of restful api for nodejs with mongoDB.
However, it seems that it cannot recognise the function findOne. Can someone point out the problem?
Error message:
TypeError: Cannot read property 'findOne' of undefined
findOne is deprecated in the latest version of mongodb#2.x
https://github.com/mongodb/node-mongodb-native/blob/2.0/lib/collection.js
You can use this query instead
find(query).limit(1).next(function(err, doc){
// handle data
})
In the first db.collection you send 3 arguments like:
db.collection(collectionName, {strict:true}, function(err, collection)
After you only send 2:
db.collection(collectionName, function(err, collection)
This should be your issue.
change the start of your code to
var mongo = require('mongodb');
mongo.BSONPure = require('bson').BSONPure;
var databaseName = 'Starter',
collectionName = 'wines';
var Server = mongo.Server,
Db = mongo.Db,
BSON = mongo.BSONPure;
use this
collection.findOne({'_id':new mongo.ObjectID(id)}, function(err, item) {
instead of
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
in your wine.js file
try to log collection to the console before using findOne or wrapping the whole thing in an:
if(err){log}
else{findone}
if(err){
console.log(err)
}
else{
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item){
res.send(item);
}}
the reason it is not working is because collection in your error-first callback function is the parameter that gets assigned if the operation is successful ...
Useful link about the topic ....
You represent your collection in a variable called collectionName and you are trying to invoke findOne() on something called collection which wont work.
instead of :
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item)
use:
collectionName.findOne({'_id':new BSON.ObjectID(id)}, function(err, item)

.push() not adding MongoDB objects to array

I have set up node and mongodb and have imported some yelp data into mongo. When I query using the mongo shell, I can see there are documents and everything is fine. However I'm unable to pass them along by adding them to an array and returning that array. When I hit up localhost:3000/api/reviews, I get a blank page. My console does log everything though so the node driver for mongo is working in getting the documents. Any ideas? I feel like it has something to do with the asynchronous nature of node.
var express = require('express');
var router = express.Router();
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var url = 'mongodb://localhost:27017/YelpDB';
var getReviews = function(db, callback) {
var cursor = db.collection('reviews').find( );
//JSONArray jsonarray = new JSONArray();
var data = [];
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
var jsonDoc = JSON.stringify(doc);
console.log(typeof jsonDoc);
data.push(jsonDoc);
} else {
callback();
}
});
return data;
};
router.get('/reviews/', function(req, res, next) {
//res.send('respond with a resource');
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
var data = getReviews(db, function() {
db.close();
});
res.json({"reviews": data});
});
});
Please try this one, you should return the data at the end of cursor.each in the callback function.
var getReviews = function(db, callback) {
var cursor = db.collection('reviews').find( );
var data = [];
cursor.each(function(err, doc) {
if (err)
callback(err);
if (doc) {
var jsonDoc = JSON.stringify(doc);
console.log(typeof jsonDoc);
data.push(jsonDoc);
} else {
// at the end of cursor, return the data through callback
callback(null, data);
}
});
};
router.get('/reviews/', function(req, res, next) {
//res.send('respond with a resource');
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
getReviews(db, function(err, data) {
if (err)
throw err;
// send the data in callback function
res.json({"reviews": data});
db.close();
});
});
});

Resources