var connection_string = 'localdb'; //local db by default
var mongojs = require('mongojs');
var collections = ['projects', 'homeAnimationData'];
var db = mongojs(connection_string, collections);
db.homeAnimationData.save({image: '/imagea', width: '200px'}, function(err, saved) {
if( err || !saved ) console.log('not saved');
else console.log('Saved');
});
db.homeAnimationData.find({}).limit(10).forEach(function(err, doc) {
if (err) throw err;
if (doc) {
console.dir(doc);
}
});
None of the consoles are working in nodejs app and I'm not getting any error?
I supect that you are actually calling db.close() but not telling us about it in your question. That, and the case of not seeing the output when you go to .find() data is primarily a problem of the fact that the methods here are 'asynchronous`, and you need to "wait" for the callback execution that you want.
Also the .forEach() method here should be used "sparingly", as it is almost never what you really want in production code. Here is the same thing that works fine with a little async flow control help from the "async" library:
var localdb = 'localdb',
async = require('async'),
mongojs = require('mongojs'),
collections = ['projects','homeAnimationData'],
db = mongojs(localdb,collections);
async.series(
[
function(callback) {
db.homeAnimationData.remove({},callback);
},
function(callback) {
var data = { "image": "/imagea", "width": "200px" };
db.homeAnimationData.save(data,function(err,saved) {
if (err) callback(err);
console.log('Saved');
callback();
});
},
function(callback) {
db.homeAnimationData.find({}).limit(10).toArray(function(err,docs) {
if (err) callback(err);
console.dir(docs);
callback();
});
}
],
function(err) {
if (err) throw err;
db.close();
}
);
Or alternately to calling the .toArray() method, you can use the "stream" interface, which is natively provided:
var localdb = 'localdb',
async = require('async'),
mongojs = require('mongojs'),
collections = ['projects','homeAnimationData'],
db = mongojs(localdb,collections);
async.series(
[
function(callback) {
db.homeAnimationData.remove({},callback);
},
function(callback) {
var data = { "image": "/imagea", "width": "200px" };
db.homeAnimationData.save(data,function(err,saved) {
if (err) callback(err);
console.log('Saved');
callback();
});
},
function(callback) {
var cursor = db.homeAnimationData.find({}).limit(10);
cursor.on('data',function(data) {
cursor.pause();
console.dir(data);
cursor.resume();
});
cursor.on('err',callback);
cursor.on('end',callback);
}
],
function(err) {
if (err) throw err;
db.close();
}
);
In the latter case, this gives you a lot better handling for larger results. The mongojs documtation itself provides and example of .pipe() for a JSONStream.
But everything works fine, you just have to remember this is "async" programming, and logically wait for execution to complete before moving on to some like "reading" the written data back, or indeed closing the database connection.
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);
});
I have a function which uses async.parallel function to call two functions. But I don't know how to handle errors when async.parallel is used. If one of the two functions throw errors, how do I handle them?
exports.getProductconfigWithProductList = function(req, res){
var apiVersion = req.param('version', null);
var product_id = req.params.productId;
dbDriver = determineDriver('es');
async.parallel([
function(callback) {
dbDriver.getProductconfig(product_id,function(data){
callback(null, data);
});
},
function(callback) {
var productListPromise = getProductListData();
productListPromise.then(function(data) {
callback(null, data);
});
}
],
function(err, results) {
if(!err){
var data = results[0];
data[1] = results[1];
res.send(data);
res.end();
} else {
console.log('<<<<<<<<<<<<<<'+err+'>>>>>>>>>>>>>>>');
res.send(err);
res.end();
}
}
);
};
When you have:
async.parallel([
func1,
func2,
], (err, data) => {
if (err) {
// you handle the errors here
}
});
It's explained in more detail in the docs:
https://caolan.github.io/async/docs.html
and in the issue on GitHub here:
https://github.com/caolan/async/issues/334
I have a site where i need some data from my Mongo data to be shown. My problem, however, is that i need data from two collections. Collections that are completely separate and have nothing to do with each other.
Right now i have this in my routes for my profile-page:
router.get('/profile', function(req, res,next) {
var resultArray = [];
mongo.connect(url, function(err, db) {
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err) {
resultArray.push(doc);
}, function() {
db.close();
res.render('profile/index', {users: resultArray});
});
});
});
And this, of course, works perfectly fine. But how do i get a second db.collection('colors').find(); to be passed along to my template too?
I'm sure it's something trivial, and me just not quite having the full grasp of things, but yeah.. I'm stuck..
Use the async library which is best suited for this scenario. Where you need to run multiple tasks that do not depend on each other and when they all finish do something else, you should use async.parallel() method. The signature is async.parallel(tasks, callback), where tasks is an array of functions.
It will immediately run all the functions in parallel, wait for all of them to call their task callback, and finally when all tasks are complete it will run callback (the final callback).
The following example demonstrates how this could be adapted for your use case:
router.get('/profile', function(req, res, next) {
mongo.connect(url, function(err, db) {
var locals = {};
var tasks = [
// Load users
function(callback) {
db.collection('users').find({}).toArray(function(err, users) {
if (err) return callback(err);
locals.users = users;
callback();
});
},
// Load colors
function(callback) {
db.collection('colors').find({}).toArray(function(err, colors) {
if (err) return callback(err);
locals.colors = colors;
callback();
});
}
];
async.parallel(tasks, function(err) { //This function gets called after the two tasks have called their "task callbacks"
if (err) return next(err); //If an error occurred, let express handle it by calling the `next` function
// Here `locals` will be an object with `users` and `colors` keys
// Example: `locals = {users: [...], colors: [...]}`
db.close();
res.render('profile/index', locals);
});
});
});
Try this code:
router.get('/profile', function(req, res,next) {
var resultArray = {
users : [],
colors : []
};
mongo.connect(url, function(err, db) {
var cursor = db.collection('users').find();
cursor.forEach(function(doc, err) {
resultArray.users.push(doc);
}
var colors = db.collection('colors').find();
colors.forEach(function(doc,err){
resultArray.colors.push(doc);
}, function() {
db.close();
res.render('profile/index', {users: resultArray.users, colors: resultArray.colors});
});
});
});
Didn't have time to check it, but I'm pretty sure that it would work.
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);
});
};
here is my model code to insert some records. On my work pc it works perfectly, but when I'm running it on my home pc with the same OS, collection.insert doesn't running its callback, so I get just long request which ends with time out. There are no errors, mongo db logs say "Connection accepted" 5 times, and after that there are no messages. The same happens when I try to fetch objects from database using find(). Inserting records with mongo shell works great, but with node.js I couldn't accomplish that.
/*
* POST populate locations.
*/
var MongoClient = require('mongodb').MongoClient,
_ = require('underscore'),
env = process.env.NODE_ENV || 'development',
config = require('../config/config')[env]
exports.connect = function(cb) {
MongoClient.connect(config.db, function(err, db) {
if (err) throw err;
cb(db)
});
}
exports.populate = function(data, cb) {
var self = this;
self.connect(function(db) {
var collection = db.collection('locations');
collection.insert(data, function(err, docs) {
collection.ensureIndex({
"loc": "2dsphere"
}, function() {
db.close();
cb();
});
});
});
}
Use
exports.populate = function(data, cb) {
MongoClient.connect(config.db, function(db) {
var collection = db.collection('locations');
collection.insert(data, function(err, docs) {
collection.ensureIndex({
"loc": "2dsphere"
}, function() {
db.close();
cb();
});
});
});
}