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);
});
}
Related
I am new to JS. here is my function, so when I use this, it will return an empty list.
if I replace resultArray.push(result); with console.log(result); it will correctly show me the result.
I am expecting to see the function return the query result inside a list.
function queryMongo (key) {
var url = "mongodb://user:pw/task?replicaSet=bdb";
var resultArray = [];
// connect to the mongoDB
MongoClient.connect(url, { useUnifiedTopology: true }, function(err, db) {
if (err) throw err;
var dbo = db.db("task");
var query = { 'device' : key };
var cursor = dbo.collection('commands').find(query);
cursor.forEach(function(result){
if (err) throw err;
resultArray.push(result);
}, function(){
db.close();
})
});
return resultArray;
}
As shown in here one way would be to get the whole dataset at once:
async function queryMongo(key) {
var url = 'mongodb://user:pw/task?replicaSet=bdb'
// connect to the mongoDB
return new Promise(function (resolve, reject) {
MongoClient.connect(url, { useUnifiedTopology: true }, function (err, db) {
if (err) throw err
var dbo = db.db('task')
var query = { device: key }
// Fetch all results
dbo
.collection('commands')
.find(query)
.toArray(function (err, items) {
if (err) {
return reject(err)
}
resolve(items)
db.close()
})
})
})
}
async function doWork() {
// without "async" keyword it's not possible to "await" the result
console.log(await queryMongo('some-key'))
}
doWork();
Please take following advices into consideration:
Don't connect/disconnect at each function call aside if you're performing queryMongo() once in a while
The reason your code was not working is because you were returning the result before the async call was actually finished. Hence when doing queryMongo() result was straightly []. Indeed, establishing the connection to mongo and performing the query takes "time" and NodeJS will continue performing code execution while this is happening. I would advise to read a bit around the event loop to understand this mechanic a bit better.
I think that the main problem is that all db calls are asynchronous. You can't just return the value, you can pass to a callback or return Promise.
const MongoClient = require('mongodb').MongoClient;
function queryMongo(key, callback) {
const url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useUnifiedTopology: true }, function(err, db) {
if (err) throw err;
const dbo = db.db('tasks');
const query = { device: key };
dbo
.collection('commands')
.find(query)
.toArray((err, doc) => {
if (err) throw err;
db.close();
callback(doc);
});
});
}
queryMongo(12, doc => {
/* do something */
console.log(doc);
});
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
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();
});
});
});
I am writing the filter using mongodb native driver, but it's driving me this error when you run the query.
In the case of this driver, it has no exec?
What is another way to perform this query?
exports.findAll = function(req, res) {
MongoClient.connect(url, function(err, db) {
var section = req.params.section;
var collection = db.collection(section);
var filter = req.query.filter ? {nameToLower: new RegExp('^' + req.query.filter.toLowerCase())} : {};
var query = collection.find(filter);
var count = 0;
collection.count(filter, function (error, result) {
count = result;
});
if(req.query.order) {
query.sort(req.query.order);
}
if(req.query.limit) {
query.limit(req.query.limit);
if(req.query.page) {
query.skip(req.query.limit * --req.query.page);
}
}
query.exec(function (error, results) {
res.json({
count: count,
data: results
});
});
});
};
Error:
TypeError: undefined is not a function
Better to use the async library in this case as it simplifies the code. In the case where you need to run multiple tasks that depend on each other and when they all finish do something else, use the
async.series() module. The following demonstrates how you can go about this in your case:
exports.findAll = function(req, res) {
var locals = {},
section = req.params.section,
filter = !!req.query.filter ? {nameToLower: new RegExp('^' + req.query.filter.toLowerCase())} : {};
async.series([
// Connect to DB
function(callback) {
MongoClient.connect(url, function(err, db) {
if (err) return callback(err);
locals.collection = db.collection(section); //Set the collection here, so the next task can access it
callback();
});
},
// Get count
function(callback) {
locals.collection.count(filter, function (err, result){
if (err) return callback(err);
locals.count = result; //Set the count here
callback();
});
},
// Query collection
function(callback) {
var cursor = locals.collection.find(filter);
if(req.query.order) {
cursor = cursor.sort(req.query.order);
}
if(req.query.limit) {
cursor = cursor.limit(req.query.limit);
if(req.query.page) {
cursor = cursor.skip(req.query.limit * --req.query.page);
}
}
cursor.toArray(function(err, docs) {
if (err) return callback(err);
locals.docs = docs;
callback();
});
}
], function(err) { //This function gets called after the three tasks have called their "task callbacks"
if (err) return next(err);
// Here locals will be populated with 'count' and 'docs'
res.json({
count: locals.count,
data: locals.docs
});
res.render('user-profile', locals);
});
};
I am working with node.js using express and mongoDb.
I am trying to retrieve data from database "local" and collection "borrower" and pushing it into an empty array collectionOne. It is rendering this array on the view page.
I want to use _id pushed in an array b_ids from this output to make a call to company_details collection under same router .
The issue I am facing here is I am not getting any value in array b_ids when trying to access it under call to company_details collection.
The code is as below:
var collectionOne = [];
var collectionTwo = [];
var b_ids = [];
router.get('/fetch',function(req, res, next){
MongoClient.connect('mongodb://localhost:27017/local', function(err, db){
var collection = db.collection('borrower');
db.collection("borrower", function(err, collection) {
collection.find().toArray(function(err, result) {
if (err) {
throw err;
} else {
//console.log(result[0].first_name);
for (i=0; i<result.length; i++) {
collectionOne[i] = result[i];
b_ids[i] = result[i]._id;
}
}
});
db.collection("company_details", function(err, collection){
console.log(b_ids);
collection.find({borrower_id : {$in :b_ids}}).toArray(function(err, result){
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionTwo[i] = result[i];
}
}
});
});
res.render('index',{data : collectionOne , data1 : collectionTwo});
});
});
});
Please suggest me how can I access the b_ids array here. Thanks in advance :)
The callback from toArray is asynchronous, i.e. will happen after your console.log line executes, therefore you need to re-arrange as follows:
var collectionOne = [];
router.get('/fetch',function(req, res, next){
MongoClient.connect('mongodb://localhost:27017/local', function(err, db){
var collection = db.collection('borrower');
db.collection("borrower", function(err, collection) {
collection.find().toArray(function(err, result) {
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionOne[i] = result[i];
b_ids[i] = result[i]._id;
}
db.collection("company_details", function(err, collection){
console.log(b_ids);
collection.find({borrower_id : {$in :b_ids}}).toArray(function(err, result){
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionTwo[i] = result[i];
}
res.render('index',{data : collectionOne , data1 : collectionTwo});
}
});
});
}
});
});
});
This ensures that the callback completes before you try and log / render it.
It is simple create a function with a callback function inside it as an argument
function returnBids(collection, callback){
collection.find().toArray(function(err, result) {
if (err)
throw err;
else
callback(result)
})
}
and you can access your result outside by calling the function returnbids() .i.e
returnBids(collection,function(b_ids){
console.log(b_ids)
})