NodeJS With Mongo: Callback Is Not A Function error - node.js

Im currently working on a NodeJS/Mongo project where I need to pull all the documents from a collection. I currently have the following code written:
var Db = require('mongodb').Db,
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server,
ReplSetServers = require('mongodb').ReplSetServers,
ObjectID = require('mongodb').ObjectID,
Binary = require('mongodb').Binary,
GridStore = require('mongodb').GridStore,
Grid = require('mongodb').Grid,
Code = require('mongodb').Code,
assert = require('assert');
var server = new Server('[server]', 27017);
var authDB = new Db('admin', server);
var DB1250 = new Db('1250', server);
var findDocuments = function (callback) {
authDB.authenticate("Username", "Password");
DB1250.open(function (error, db) {
if (error) {
console.log(error);
}
else {
console.log("successfully accessed: ", db);
callback;
var cursor = db.collection('Patients').find();
console.log('cursor ', cursor);
cursor.forEach(function (error, document) {
if (error) {
console.log('Document does not exist. Error: ', error);
}
else {
console.log('Document: ', document);
}
});
}
});
};
findDocuments(function (data) {
});
I am able to authenticate/connect to the server, connect to the DB, and connect to the collection. When I enter the forEach loop to iterate through all the documents, I keep getting the error "Callback is not a function". Can you guys see what I am doing wrong?

I believe the cursor you have there has not resolved into an array, so forEach is not a valid method. You might be looking for eachAsync, which will wait for the query to return before iterating.
Alternatively, you can wait for the query promise to resolve, ie:
cursor.then(docs => docs.forEach(callback));
which I personally find a little clearer.

Heres the solution I came up with after using Mongoose:
var Db = require('mongodb').Db,
MongoClient = require('mongodb').MongoClient,
Server = require('mongodb').Server,
ReplSetServers = require('mongodb').ReplSetServers,
ObjectID = require('mongodb').ObjectID,
Binary = require('mongodb').Binary,
GridStore = require('mongodb').GridStore,
Grid = require('mongodb').Grid,
Code = require('mongodb').Code,
Mongoose = require('mongoose');
assert = require('assert');
var findDocuments = function (callback) {
var options = { server: { socketOptions: { keepAlive: 1000 } } };
var connectionString = 'mongodb://username:password#server:27017/admin';
// Connected handler
Mongoose.connect(connectionString, function (err) {
var db = Mongoose.connection.useDb('db');
var collection = db.collection("collection");
collection.find().stream()
.on('data', function (document) {
console.log(document);
})
.on('error', function (err) {
// handle error
console.log(err);
})
.on('end', function () {
// final callback
});
});
// Error handler
Mongoose.connection.on('error', function (err) {
console.log(err);
});
// Reconnect when closed
Mongoose.connection.on('disconnected', function () {
self.connectToDatabase();
});
};
findDocuments(function () {
db.close();
});

cursor.forEach() is an asynchronous operation but returns nothing. So you shouldn't do db.close() or likewise below the line somethere synchronously.
Besides; I am not sure which version Node driver you are refering to but in the recent ones like v3+ cursor.forEach() doesn't take an error first type callback like the one that you use in your code. It will take an "iterator" and an "end" callback such as;
cursor.forEach(doc => console.log(doc),
err => err ? console.log(err)
: db.close())
So the above code will just work fine, iterating and processing the documents one by one as they appear without waiting up until all of them have been retrieved to the memory.

Related

async await is not executing functions sequentially in express nodejs

I want to run 3 database query then render the 3 result objects to view, so I used async await to run queries first but seems its not waiting/working, always sending null objects to view before running queries. Cant find where I went wrong, I am using nodejs 12.16.1, not sure if its es6 supporting issue or sth else.
var express = require('express');
var router = express.Router();
var reviewModel = require.main.require('./models/review-model');
var propertyModel = require.main.require('./models/property-model');
router.get('/', async function(req, res){
try{
req.cookies['username'] == null ? loginCookie = null : loginCookie = req.cookies['username'];
var getPromoteInfo = await propertyModel.getPromoteInfo(function(result){
if(result!=null) return result;
});
var getPromoteReview = await reviewModel.getPromoteReview(function(result2){
if(result2!=null) return result2;
});
var getLatest3reviews = await reviewModel.getLatest3reviews(function(result3){
if(result3!=null) return result3;
});
res.render('index', {property:getPromoteInfo, rating:getPromoteReview, testimonials:getLatest3reviews, loginCookie});
}
catch(err){console.log(err);}
});
module.exports = router;
Model code:
var db = require('./db');
module.exports = {
getPromoteInfo: function(callback){
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
callback(result);
}else{
callback(null);
}
});
}
}
You're using await on a function that does not return a Promise resulting in an undefined value. So in order for async/await to work, you could rewrite getPromoteInfo as follows:
var db = require('./db');
module.exports = {
getPromoteInfo: function(){
return new Promise( (resolve, reject) => {
var sql = "select * from property where promote_status = 1;";
db.getResult(sql, null, function(result){
if(result){
resolve(result);
}else{
// you can decide whether to reject or not if no records were found
reject();
}
});
});
}
}
In your express-handler you can then simply await this function call, without passing a callback:
const getPromoteInfo = await propertyModel.getPromoteInfo();
Note that you can check if your db-client/library supports promises out of the box - then you would not have to wrap your functions manually in a promise.

Using durable functions in azure function app with mongodb

I have a mongoDB which contains the time where in my durable function should run (e.g. 8:00, 9:01, 10:20). Now I have my Orchestrator code below, nothing works inside the mongoClient.connect. Why???
const df = require("durable-functions");
const moment = require("moment");
const mongoClient = require("mongodb").MongoClient;
module.exports = df.orchestrator(function*(context) {
context.log("Getting time schedules in DB");
var timeSched = [];
var dbName = <dbName>;
var collectionName = <collectionName>;
var query = {id: "1"};
try{
mongoClient.connect(<mongoDB_connection_string>,{useNewUrlParser: true, authSource: dbName}, function (err, client) {
//Anything inside this does not log or work
if(err){
context.log(`Error occurred while connecting to DB ${err}`)
return context.done();
}else{
context.log('MongoClient connected to DB');
}
var collection = client.db(dbName).collection(collectionName);
collection.find(query).toArray(function(err, result) {
if (err) throw err;
for(let i = 0; i < result.length; i++){
timeSched.push(result[i].time); //e.g.8:00
}
client.close();
//This should log [8:00,9:01,10:01] but it does not log
context.log(timeSched);
context.done();
});
});
//This logs 0
context.log(timeSched.length);
for (let j = 0; j < timeSched.length; j++) {
const deadline = moment.utc(context.df.currentUtcDateTime).add(3, 'minutes');
yield context.df.createTimer(deadline.toDate());
yield context.df.callActivity("ActivityFunction",timeSched[j]);
}
context.done();
}catch(e){
context.log(`Error ${e}`);
context.done();
}
});
Try the code below to check if you can connect to DB first. Use console.log instead of context.log.
const df = require("durable-functions");
const mongoClient = require("mongodb").MongoClient;
module.exports = df.orchestrator(function*(context) {
var mongoClient = require("mongodb").MongoClient;
mongoClient.connect(
"mongodb://tonytest:78jst6Mh****.documents.azure.com:10255/?ssl=true",
function(err, client) {
if (err) {
console.log(`Error occurred while connecting to DB ${err}`);
return context.done();
} else {
console.log("MongoClient connected to DB");
}
client.close();
}
);
});
Try with console.log(timeSched); to output timeSched. Besides, when you execute console.log(timeSched.length);, timeSched hasn't been granted value. That's why you got 0;

Gather multiple functions output on single route call and render to html in nodejs

Newbie to nodejs,trying to execute multiple functions output to html using nodejs,express and mysql as backend.Need to execute 20 functions on single routing call to combine the output of 20 functions and render as json to html.
My app.js function
var express = require('express');
var router = express.Router();
var path = require('path');
var app = express();
var todo = require('./modules/first');
var todo1 = require('./modules/second');
var connection = require('./connection');
connection.init();
app.get('/', function(req,res,next) {
Promise.all([todo.class1.getUsrCnt(),todo.class1.getTotlAmt(),todo.class1.getTotlOrdrCnt(),todo.class1.getTotlCntRcds(),todo.class1.getTotlScsRcds(),todo.class1.getTotlFailRcds(),todo.class1.getTotlAmtRcds()])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
app.get('/second', function(req,res,next) {
Promise.all([todo1.class2.getUsr........])
.then(function(allData) {
res.addHeader("Access-Control-Allow-Origin", "http://hostname:8183/");
res.json({ message3: allData });
});
res.send(send response to html);
})
var server = app.listen(8183, function(){
console.log('Server listening on port '+ server.address().port)
});
My todo.js is
var connection = require('../connection');
var data = {},obj={};
var d = new Date();
var month = d.getMonth() + 1;
var year = d.getFullYear();
obj.getUsrCnt = function getUsrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query1, function(err, result) {
con.release();
data.usrs_cnt = result[0].some;
})
});
}
obj.getTotlAmt = function getTotlAmt(callback) {
connection.acquire(function(err, con) {
con.query(query2, function(err, result) {
con.release();
data.total_amt = result[0].some1;
})
});
}
obj.getTotlOrdrCnt = function getTotlOrdrCnt(callback) {
connection.acquire(function(err, con) {
con.query(query3, function(err, result) {
con.release();
data.total_orders = result[0].some2;
})
});
}
.
.
. functions go on
exports.class1 = obj;
Getting undefined in the promise all and unable to render to the html file.
Not sure about the code you wrote, but as I understand you want to call all the functions, get all the results and return back to the user?
so you can use many libraries that waits for several calls for example, promise based:
Promise.all([todo.getUsrCnt('dontcare'), todo.getTotlAmt('dontcate')])
.then(function(allData) {
// All data available here in the order it was called.
});
as for your updated code, you are not returning the data as promises, you assigning it to the local variable.
this is how your methods should look:
obj.getUsrCnt = function getUsrCnt(callback) {
var promise = new Promise(function(resolve, reject) {
connection.acquire(function(err, con) {
if(err) {
return reject(err);
}
con.query(query1, function(err, result) {
con.release();
resolve(result[0].some);
})
});
});
return promise;
}
as you can see here, I am creating a new promise and returning it in the main function.
Inside the new promise I have 2 methods: "resolve", "reject"
one is for the data and one is for errors.
so when you use the promise like this:
returnedPromise.then(function(data) {
//this data is what we got from resolve
}).catch(function(err) {
//this err is what we got from reject
});
you can see that a promise can or resolved or rejected,
do this to all the methods, and then you start seeing data

Nodejs MySQL connection timeout

When I run the application, It shows me Database is connected!
db.js
var mysql = require('mysql');
var settings = require('./config');
var db;
var exports = {};
exports.connectdb = function () {
db = mysql.createConnection(settings.Database);
db.connect(function(err){
console.log('connecting');
if(!err) {
console.log('Database is connected!');
return db;
} else {
console.log('Error connecting database!'+err);
return null;
}
});
};
module.exports = exports;
but when i am trying to connect DB from user.js it shows me connection is null / TypeError: Cannot read property 'query' of undefined.
code block from user.js
var exports = {};
var dbcon = require('../config/db.js');
var dbconn = dbcon.connectdb();
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
var dbconn = dbcon.connectdb();
if ( dbconn == null ) console.log('still nul');
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
return null;
}
});
};
module.exports = exports;
Node.js is asynchronous by nature. You are trying to use it in a synchronous fashion. To make this work, you must use the callback pattern. Below is an example:
db.js
var mysql = require('mysql');
var settings = require('./config');
var exports = {};
exports.connectdb = function (callback) {
var db = mysql.createConnection(settings.Database);
db.connect(function(err){
callback(err,db);
});
};
module.exports = exports;
user.js
var exports = {};
var dbcon = require('../config/db.js');
exports.login = function(email,password) {
var userdetails = { name:email, password:password};
dbcon.connectdb(function(err, dbconn){
if ( err) //handle error
dbconn.query("SELECT * FROM users where email = '"+email+"' and password = '"+password +"'", function (err, result) {
if(err)
{
console.log(result[0]+' err');
}
});
});
};
module.exports = exports;
From the code above you can see how the connectdb function accepts a function callback. When the database is connected the code will execute that callback to send the results. In the user.js file, you can now pass a callback function and use the results it gives you (the db). You can find more info about Node.js' asynchronous nature here. Basically, asynchronous code uses callbacks and synchronous code uses return statements. Returning values from asynchronous functions will most always yield null results as asynchronous callbacks will always fire "sometime" after the function is called.

Query database connection from another Node.js module

Dumb question... I am working (i.e. learning) with an API in Node.js and connecting to MongoDB using the code below. Everything works great while the database code is located inside my routes.js file, but I would really like to move that code block out to a separate dbconfig.js file/module.
I've tried every method I can find, but the db variable/object always returns undefined when called inside my getQuery function. Any guidance would be greatly appreciated!!!
dbconfig.js
module.exports=function() {
var db;
var mongoClient = require('mongodb').MongoClient;
var mongoUrl = 'mongodb://username:password#ds123456.mongolab.com:123456/mydb';
var mongoOptions = {
server: {auto_reconnect: true}
};
getDb();
return {
db: this.db
};
function getDb() {
mongoClient.connect(mongoUrl, mongoOptions, function(error, database) {
if (error) {
console.log(error)
} else {
db = database;
}
});
}
};
routes.js (Relevant portion)
(function(routes) {
var dbconfig = require('.\dbconfig')();
var breezeMongo = require('breeze-mongodb');
var db = dbconfig.db;
function getQuery(request, result, next) {
try {
var resource = request.params.resource;
var collectionName = getCollectionName(resource);
var query = new breezeMongo.MongoQuery(request.query);
query.execute(db, collectionName, processResults(result, next));
} catch (ex) {
var err = {
statusCode: 404,
message: 'Unable to execute query " ' + request.url + '"',
error: ex
};
}
}
})(module.exports);

Resources