I am currently trying to learn how to use MongoDB. I tried two similar but slightly different pieces of code and received completely different results. I am trying to understand why this happened.
CODE 1
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, function(err, client) {
if (err) throw err
var db = client.db('EmployeeDB')
var cursor = db.collection('Employee').find()
cursor.forEach(function(err, doc) {
console.log(doc);
console.log("Hello")
});
client.close()
});
CODE 2
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, function(err, client) {
if (err) throw err
var db = client.db('EmployeeDB')
var cursor = db.collection('Employee').find()
cursor.forEach(function(err, doc) {
if (err) {
console.log(err)
} else {
console.log(doc);
}
});
client.close()
});
Code 1 returned "undefined \n undefined \n undefined". However, Code 2 returned the actual objects and their information. I was wondering why only the second piece of code works correctly.
There is only one argument in the callback of cursor.forEach(), not two. Hence in both cases, "doc" is not defined, and only "err" is defined (which is the actual document).
Your code should thus be:
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017';
MongoClient.connect(url, { useNewUrlParser: true }, function(err, client) {
if (err) throw err;
var db = client.db('EmployeeDB');
var cursor = db.collection('Employee').find();
cursor.forEach(function(doc) {
console.log(doc);
});
client.close();
});
From MongoDB official docs:
The signature includes a single argument that is passed the current document to process.
Source: https://docs.mongodb.com/manual/reference/method/cursor.forEach/
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);
});
So in the following functions I'm always establishing a new connection with my mongodb. How would I have to change my code so it only connects once at the beginning and not in every of these functions.
function getData(callback){
arrayOfArticles = [];
MongoClient.connect(url, { useNewUrlParser: true }, callback, function(err, db) {
if (err) throw err;
let dbo = db.db('testdb');
article = dbo.collection('testname').find({}).toArray(function(err, article) {
if (err) throw err;
db.close();
for (var i = 0, len = article.length; i < len; i++){
arrayOfArticles.push(article[i].name);
}
callback(null, arrayOfArticles);
});
});
function getPrice(callback){
arrayOfPrices = [];
MongoClient.connect(url, { useNewUrlParser: true }, callback, function(err, db) {
if (err) throw err;
let dbo = db.db('testdb');
article = dbo.collection('testcollection').find({}).toArray(function(err, arrayOfPrices) {
if (err) throw err;
db.close();
callback(null, arrayOfPrices);
});
});
function getDealerData(callback){
dealerData = [];
MongoClient.connect(url, { useNewUrlParser: true }, callback, function(err, db) {
if (err) throw err;
let dbo = db.db('Dealer');
article = dbo.collection('Dealer').find({}).toArray(function(err, dealerData) {
if (err) throw err;
db.close();
callback(null, dealerData);
});
});
It's not a good practice to create connection for every task.
I would suggest to create a separate file for create connection and available the connection on everywhere
Example
//db.js
MongoClient.connect(url, {
useNewUrlParser: true
}, callback, function (err, db) {
if (err) throw err;
global.dbo = db.db('testdb');
});
And in your main server file I am assuming app.js and require it on top for all middlewares
//app.js
<--All depandent module -->
require('db.js'); // change the path according to your structure.
And now dbo will be available to all your app and just use it everywhere.
It's also good practice to use single connection and for load, Mongo itself creates pull to handle the concurrency
As per Mongo official comment:
You open do MongoClient.connect once when your app boots up and reuse the db object. It's not a singleton connection pool each .connect creates a new connection pool. So open it once an reuse across all requests.
Update
I have tried to make your one function here
function getPrice(callback){
arrayOfPrices = [];
dbo.collection('testcollection').find({}).toArray(function(err, arrayOfPrices) {
if (err) throw err;
callback(null, arrayOfPrices);
});
}
I found this block of code, derived from the previous answer to be very useful...
Rather than a separate file it stores the collection in the app locals system.
MongoClient.connect(url, { useNewUrlParser: true })
.then(client => {
const dbo = client.db('myDB');
const collection = dbo.collection('numbers');
app.listen(port2, () => console.info(`REST API running on port ${port2}`));
app.locals.collection = collection; // this line stores the collection from above so it is available anywhere in the app, after small delay.
}).catch(error => console.error(error));
i am facing an issue while inserting data into collection.it gives an error of cannot read property of collection undefined. provide a solution of it i try my best.
here is my code.
var http = require('http');
var fs = require('fs');
var querystring = require('querystring');
var MongoClient = require('mongodb').MongoClient;
var url ="mongodb://127.0.0.1:27017/college";
var port = 4000;
http.createServer((req,res) => {
if(req.url==="/form")
{
res.writeHead(200,{"Content-Type": "text:html"});
fs.createReadStream("./public/form.html" , "UTF-8").pipe(res);
}
if(req.method==="POST")
{
var data = " ";
req.on("data", function(chunk)
{
data += chunk;
});
req.on("end" , function(chunk){
MongoClient.connect(url , function(err,db){
if(err) throw err;
var q = querystring.parse(data).
db.collection('res').insertOne(q,function(err,res){
if(err) throw err;
console.log("data is insert");
db.close();
});
})
});
}
}).listen(port);
console.log(port);
here is erro i am facing
Well I would suggest your to go this way.
1- Don't use database name in when creating mongodburl i-e
replace
var url ="mongodb://127.0.0.1:27017/college";
with
var url ="mongodb://127.0.0.1:27017/";
And now when you try to connect with mongodb server you'll get mongodb constructor in the callback function so you'll have to add one extra line of code. Something like below
MongoClient.connect(url, function (err, dbC) {
if (err) throw err;
var db = dbC.db("college");
var q = querystring.parse(data).
db.collection('res').insertOne(q, function (err, res) {
if (err) throw err;
console.log("data is insert");
db.close();
});
})
This way you'll get res collection defined for the database college (I am assuming you've already defined that collection in your database with some query like db.createCollection('res')) and then it should work
Thanks
There is a piece of code that querying data from mongodb with node.js:
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
//a query that returns all the documents
var findDocuments = function(db, callback) {
// Get the documents collection
var collection = db.collection('documents');
// Find some documents
collection.find({}).toArray(function(err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs)
callback(docs);
});
}
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
var result = findDocuments(db, function() {
db.close();
});
});
//export the query result,but it doesn't work because it is a local variable in `MongoClient.connect()`
export {result}
Question:
I want to export the variable result, but it doesn't work because it is a local variable in MongoClient.connect().What should I do?
Define it outside the function like
var result
You need to define it globally in the document.
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
var result; //define it out here to be able to use it on anywhere
//a query that returns all the documents
var findDocuments = function(db, callback) {
// Get the documents collection
var collection = db.collection('documents');
// Find some documents
collection.find({}).toArray(function(err, docs) {
assert.equal(err, null);
console.log("Found the following records");
console.log(docs)
callback(docs);
});
}
var MongoClient = require('mongodb').MongoClient
, assert = require('assert');
// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
result = findDocuments(db, function() { //give it its value
db.close();
});
});
//export the query result,but it doesn't work because it is a local variable in `MongoClient.connect()`
export {result}
If you are using ES6, I would recommend to use the keywords let/const instead of var.
Now about your issue why would you export result that way?
You should create a function connect() and export it. Then in your controller, call this function and handle whatever the outcome is.
Your connect here is totally asynchronous and uncontrolled, which is very bad behavior.
Exemple of what to do :
file mongodb.es6
export default class Mongodb {
connect() {
...
}
...
}
file main.es6
const mongodbObject = new Mongodb();
mongodbObject.connect()
.then(() => {
// I am connected so I can do whatever I want
})
.catch((err) => {
// I have an error and do something about it
});
Don't do it like this!
This will ONLY query the data when the file is being executed. I don't see any reason to do it this way.
Instead expose a function from this file, which will connect to the DB, query it and return the result object, everytime you call it.
export {
getResult: function(query, callback) {
// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the server
MongoClient.connect(url, function(err, db) {
if (err) return callback(err);
console.log("Connected correctly to server");
result = findDocuments(db, function() {
db.close();
});
callback(null, result);
});
}
}
I'm having trouble retrieving data from a mongodb collection which I believe has been inserted correctly.
So here is my example code...
var db = require('./database');
module.exports = function (app) {
app.get('/db', function (req, res) {
db.collection('myCollection', function (err, myCollection) {
if (err) {
return console.error(err);
}
var docrow = {
// no id specified, we'll let mongodb handle that
name: 'Mark',
date: '2013/09/11',
description: 'Some text here'
};
console.log('I GET HERE OK');
myCollection.insert(docrow, { safe: true }, function (err, insertedDocument) {
console.log('BUT I DONT GET HERE?');
if (err && err.name === 'MongoError' && err.code === 11000) {
return console.log('This document already exists');
} else if (err) {
return console.log('Something bad happened');
}
myCollection.find({ name: 'Mark' }, function (err, docs) {
docs.each(function (err, doc) {
console.log(doc);
});
});
});
res.end('OK we made it');
});
});
};
...and the database.js file is...
var Db = require('mongodb').Db,
Connection = require('mongodb').Connection,
Server = require('mongodb').Server;
var host = process.env['MONGO_NODE_DRIVER_HOST'] != null ? process.env['MONGO_NODE_DRIVER_HOST'] : 'localhost';
var port = process.env['MONGO_NODE_DRIVER_PORT'] != null ? process.env['MONGO_NODE_DRIVER_PORT'] : Connection.DEFAULT_PORT;
/*
w:1 tells mongo to wait until at least one confirmed write has succeeded before calling any callbacks
*/
var flags = { w: 1 };
var server = new Server(host, port, { auto_reconnect: true, poolSize: 20 });
var db = new Db('TestDBName', server, flags);
module.exports = db;
It looks like I'm able to create a Collection (myCollection) without error, and calling insert on the collection doesn't error either, but also doesn't appear to get any where near inside the callback function for it to trigger either an error or handle a success?
What am I doing wrong here?
Thanks for any help you can give me.
When you connect to mongodb it is asynchronous method, so it will return client handler in callback, and this client handler have to be used onwards instead of handle of that Db object. So change this:
var db = new Db('TestDBName', server, flags);
To this:
new Db('TestDBName', server, flags).open(function(err, client) {
if(err) throw err;
// client - is the guy you are looking for instead of `db` you had
});
As well change:
myCollection.find({ name: 'Mark' }, function (err, docs) {
To:
myCollection.find({ name: 'Mark' }).toArray(function (err, docs) {
It is the only exception with mongo-native where you have to use .toArray instead of direct callback.