Im trying to connect to my Mongodb and insert some documents if they are not already in the db. It works fine with the first inserts but in the function existInDatabase it sometimes does not execute the callback function.
var MongoClient = require('mongodb').MongoClient;
var mongoData = require('./mongoData');
var exports = module.exports = {};
var dbName = 'checklist';
MongoClient.connect(mongoData.ConString, {
useNewUrlParser: true
}, function(err, db) {
if (err) throw err;
for (var key in mongoData.Customers) {
if (!existsInDatabase(mongoData.Customers[key], 'Customers')) {
db.db(dbName).collection('Customers').insertOne(mongoData.Customers[key], function(err, res) {
if (err) throw err;
console.log('1 document inserted');
db.close();
});
}
}
for (var key in mongoData.Categorys) {
if (!existsInDatabase(mongoData.Customers[key], 'Customers')) {
db.db(dbName).collection('Categorys').insertOne(mongoData.Categorys[key], function(err, res) {
if (err) throw err;
console.log('1 document inserted');
db.close();
});
}
}
});
function existsInDatabase(obj, collection) {
var result = false;
MongoClient.connect(mongoData.ConString, {
useNewUrlParser: true
}, function(err, db) {
db.db(dbName).collection(collection).find({}).forEach(function(doc) {
if (doc.id == obj.id) {
result = true;
}
}, function(err) {
console.log(err);
});
});
return result;
}
I have made a few changes to your code. It seems you are new to async programming, spend some time to understand the flow. Feel free for any further query. Here is your code.
// Welcome to aync programming
// Here no one waits for the slow processes
var MongoClient = require('mongodb').MongoClient;
var mongoData = require('./mongoData');
var exports = module.exports = {};
var dbName = 'checklist';
// Make the connection for once only
MongoClient.connect(mongoData.ConString, { useNewUrlParser: true },
function(err, db) {
if (err) throw err;
var myDB = db.db(dbName); // create DB for once
for (var key in mongoData.Customers) {
//make call to the function and wait for the response
existsInDatabase(mongoData.Customers[key], 'Customers', function(err, result) {
//once the response came excute the next step
if (result) {
myDB.collection('Customers').insertOne(mongoData.Customers[key], function(err, res) {
if (err) throw err;
console.log('1 document inserted');
});
}
});
}
for (var key in mongoData.Categorys) {
//make call to the function and wait for the response
existsInDatabase(mongoData.Customers[key], 'Customers', function(err, result) {
//once the response came excute the next step
if (result) {
myDB.collection('Categorys').insertOne(mongoData.Categorys[key], function(err, res) {
if (err) throw err;
console.log('1 document inserted');
});
}
});
}
// Both the for loop will work randomly without any order
function existsInDatabase(obj, collection, cb) {
var result = false;
myDB.collection(collection).findOne({ id: obj.id }, function(err, result)
{
if (err) {
//this cb will work only when db operation is complited
cb(err);
} else if (result) {
cb(null, true);
} else {
cb(null, false);
}
});
}
});
This code may result in some error. Feel free to ask more questions over it
db.db(dbName).collection(collection).find({}) returns a cursor per the docs. You are missing .toArray():
db.db(dbName).collection(collection).find({}).toArray()...
Related
I want to throw an error into the console if the following function doesn't work for any reason. It's getting some data from a website, writing them into a mongoDB.
If for example the insert into mongoDB or the scraping fails I want to get an error message in the console. I have no idea how to archive proper error-handling with nodejs (0 clue about promises and stuff).
artikel.getData(async () => { for (let i = 0; i < arrayOfArticles.length; i++){
await scrape(i).then((price) => {
console.log('Data ' + arrayOfArticles[i] + ': ' + received);
//Connect to DB
MongoClient.connect(url, {useNewUrlParser: true}, function(err, db) {
if (err) throw err;
let dbo = db.db("testDB");
let insertPart = {
name: arrayOfArticles[i],
site: dealer,
price: price
};
dbo.collection("testcollection").insertOne(insertPart, function(err, res) {
if (err) throw err;
console.log(divide);
console.log("Document inserted");
console.log(divide);
db.close();
});
});
});
}
});
You should not write DB connection code inside the loop or inside API. It should be in some config file.
You don't need to write .then with await, use try-catch for error handling.
artikel.getData(() => {
MongoClient.connect(url, {
useNewUrlParser: true
}, async function (err, db) {
for (let i = 0; i < arrayOfArticles.length; i++) {
try {
const price = await scrape(i);
//Connect to DB
if (err) throw err;
let dbo = db.db("testDB");
let insertPart = {
name: arrayOfArticles[i],
site: dealer,
price: price
};
dbo.collection("testcollection").insertOne(insertPart, function (err, res) {
if (err) {
console.log(err);
throw err
};
console.log(divide);
console.log("Document inserted");
console.log(divide);
});
} catch (error) {
console.log(error);
}
}
db.close();
});
});
So I am trying out my code for updating and showing it to the user. Basically it is able to do what I need to do but after performing it I get this error
C:\Users\tester01_2\myproject\node_modules\mongodb-core\lib\cursor.js:174
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11)
at ServerResponse.header (
C:\Users\tester01_2\myproject\node_modules\express\lib\response.js:725:10)
at ServerResponse.send
(C:\Users\tester01_2\myproject\node_modules\express\lib\response.js:170:12)
at C:\Users\tester01_2\myproject\dbUpdate.js:13:14
at C:\Users\tester01_2\myproject\dbUpdate.js:28:5
at handleCallback (C:\Users\tester01_2\myproject\node_modules\mongodb-
core\lib\cursor.js:171:5)
at nextFunction (C:\Users\tester01_2\myproject\node_modules\mongodb-
core\lib\cursor.js:682:5)
at Cursor.next [as _next]
(C:\Users\tester01_2\myproject\node_modules\mongodb-
core\lib\cursor.js:692:3)
at loop
(C:\Users\tester01_2\myproject\node_modules\mongodb\lib\cursor.js:694:8)
at _each
(C:\Users\tester01_2\myproject\node_modules\mongodb\lib\cursor.js:741:16)
This is my code
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var url = 'mongodb://localhost:27017/myproject';
module.exports = {
postCollection : function(req, res){
var issueQty = req.body.issueQty;
var itemDescrip = req.body.itemDescrip;
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
updateRecord(db, req, function(doc) {
return res.send('Record Found. Now updating this document...' +
itemDescrip + ' Record Updated. This is the new record ' + doc )
res.end();
db.close();
});
});
}
}
var updateRecord = function(db, req, callback) {
var cursor = db.collection('documents').find({'Item Description':
req.body.itemDescrip, 'Issued QTY': req.body.issueQty})
cursor.each(function(err,doc){
assert.equal(err, null);
if(doc != err){
console.log('Successfully queried');
console.log(doc);
callback(JSON.stringify(doc));
} else{
throw err;
}
});
db.collection('documents').updateMany(
{ 'Item Description': req.body.itemDescrip},
{
$set: { 'Issued QTY': req.body.issueQty }
},function(err, results) {
console.log(results);
console.log('Done');
console.log(results);
});
};
I think it has to do with my res due to all the threads I have seen being res being in a wrong position but I need to put my res.send there so that it can use doc. Is there any way to solve this problem? Thanks.
Firstly, you should remove return in front of res.send().
Secondly, in updateRecord function, the callback function shouldn't be called in a loop, it will execute multiple times. And you close the db before you execute updateMany.
If you want to send doc, you should use a temp array to hold the doc, and pass it to res when you finish all logics in updateRecord.
If I understand you correctly, following is my modification of your codes,
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/myproject';
var updateRecord = function(db, req, callback) {
db.collection('documents').updateMany({ 'Item Description': req.body.itemDescrip }, {
$set: { 'Issued QTY': req.body.issueQty }
}, function(err, results) {
if (err) return callback(err);
console.log('Done');
console.log(results);
var cursor = db.collection('documents').find({
'Item Description': req.body.itemDescrip,
'Issued QTY': req.body.issueQty
});
var temp = [];
cursor.each(function(err, doc) {
if (err) {
return callback(err);
}
console.log('Successfully queried');
console.log(doc);
temp.push(JSON.stringify(doc));
});
callback(null, temp);
});
};
module.exports = {
postCollection: function(req, res) {
var issueQty = req.body.issueQty;
var itemDescrip = req.body.itemDescrip;
MongoClient.connect(url, function(err, db) {
if(err) {
res.send(err);
res.end();
db.close();
return;
}
updateRecord(db, req, function(err, docs) {
if(err){
res.send(err);
}
else{
res.send(docs);
}
res.end();
db.close();
});
});
}
}
I am using MongoDB to insert a record into the database, every time the post method is called. I know I do not want to connect to the db inside of the post function every time, but this is giving me errors? How can I correct this?
var mongo = require('mongodb');
var url = 'mongodb://localhost:27017/Wedding'
var db = function() {
mongo.connect(url, function(err, db){
if (!err){
return db;
}
});
}
app.post('/rsvp', function (req, res) {
var item ={
name: req.body.name,
attending: req.body.attending,
};
insertItem(item);
res.sendFile(path.join(__dirname + '/confirm.html'));
})
function insertItem(item){
db.collection('rsvpList').insertOne(item, function(err, result){
assert.equal(null, err);
})
}
I am getting this error:
TypeError: Object function () {
mongo.connect(url, function(err, db){
if (!err){
return db;
}
});
} has no method 'collection'
at insertItem (C:\Users\A587092\Documents\weddingWebsite\server.js:53:8)
at app.listen.host (C:\Users\A587092\Documents\weddingWebsite\server.js:38:4)
at Layer.handle [as handle_request] (C:\Users\A587092\Documents\weddingWebsite\node_modules\express\lib\router\layer.js:95:5)
The problem is your db does not point to the Mongo instance rather to a function!
Try this -
var mongo = require('mongodb');
var url = 'mongodb://localhost:27017/Wedding'
var db;
mongo.connect(url, function(err, connectedDB){
if (!err){
db = connectedDB;
}
});
You couldn't simply return a value from an asynchronous method:
You should use a callback function:
var connectDb = function(url, cb) {
mongo.connect(url, function(err, db){
if ( err ) {
cb( err );
}
cb(null, db);
});
};
Usage:
function insertItem(item) {
connectDb(url, function(error, db) {
if ( error ) {
throw error;
}
db.collection('rsvpList').insertOne(item, function(err, result) {
assert.equal(null, err);
});
});
}
Or a promise:
var connectDb = function(url) {
return new Promise(function(resolve, reject) {
mongo.connect(url, function(err, db){
if ( err ) {
reject(err);
}
resolve(db);
});
});
};
Usage:
function insertItem(item) {
connectDb(url)
.then(function(db) {
db.collection('rsvpList').insertOne(item, function(err, result) {
assert.equal(null, err);
});
}, function(err) {
throw err;
});
}
I change the function name from db to connectDb because we want to connect to db and then doing something after connecting. and this way your code reads well.
Also note that here also your insertItem function doing an asynchronous task so if you need the result outside of this function you should implement a similar approach, i leave it to you ;)
In node.js I am writing query to insert document to collection, but that query inserting only one document. Below the js code is,
app.js
router.post('/creatList', function(req,res){
console.log(req.body.email);
var emails = req.body.email;
if(req.body.wData.wishListType == 'Shared'){
var findUsers = function(db, callback) {
var cursor;
cursor = db.collection('users').find({email: { $in: emails }})
cursor.toArray(function(err, docs){
if(err){
callback(new Error("Some problem"));
} else {
callback(null,docs);
}
});
};
MongoClient.connect(config.database, function(err, db) {
assert.equal(null, err);
findUsers(db, function(err,docs) {
db.close();
console.log(docs);
var inserts_processing = 0;
for(var key in docs){
console.log(key);
var ids = docs[key]._id;
inserts_processing++;
console.log(ids);
var insertDocument = function(db, callback) {
db.collection('notifications').insertOne({
"userId" : ids,
},function(err, result) {
inserts_processing--;
assert.equal(err, null);
console.log("Inserted a document into the notifications collection.");
if(inserts_processing == 0){
db.close();
callback();
}
});
};
MongoClient.connect(config.database, function(err, db) {
assert.equal(null, err);
insertDocument(db, function() {
db.close();
});
});
}
});
});
} else {
console.log("other");
}
});
In the above code console.log contains two ids 570dec75cf30bf4c09679deb
56fe44836ce2226431f5388f but actually it inserting only last one.
According to your updated code I will try the following
router.post('/creatList', function(req,res){
console.log(req.body.email);
var emails = req.body.email;
if(req.body.wData.wishListType == 'Shared'){
// Open one connection to find users and insert documents
MongoClient.connect(config.database, function(err, db) {
assert.equal(null, err);
if(!err){
findUsers(db, function(err,docs) {
if(!err){
insertDocs(db, docs, function(){
db.close(); // Close connection
console.log("All documents have been inserted");
res.status(200).send("All is OK");
});
}
});
});
}
} else
console.log("other");
});
function insertDocs(db, docs, callback){
var inserts_processing = 0; // Will contain the number of inserts pending operation
for(var key in docs){
var ids = docs[key]._id;
inserts_processing++; // Before writing data, add one to processing inserts
db.collection('notifications').insertOne({
"userId" : ids,
}, function(err, result) {
inserts_processing--; // One insert have been finished, so remove one
assert.equal(err, null);
console.log("Document inserted into the notifications collection.");
// If all inserts have been finished, call back the function
if(inserts_processing == 0)
callback();
});
}
}
function findUsers(db, callback) {
var cursor;
cursor = db.collection('users').find({email: { $in: emails }})
cursor.toArray(function(err, docs){
if(err)
callback(new Error("Some problem"));
else
callback(null,docs);
});
};
router.get('/roomlist', function(req, res) {
var db = req.db;
var collection = db.get('roomlist');
collection.find(function(e,docs){
res.render('roomlist', {
"roomlist" : docs
});
});
});
The above controller is used to get list of rooms under a table "ROOMLIST". I need to get the details. I need to display all the roomname in the table ROOMLIST.
You should use find method of mongodb to get the documents from a collection. And then use cursor to iterate through the documents.
var getRoomlist = function(db, callback) {
var cursor =db.collection('roomlist').find( );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
return callback(false, doc);
} else {
return callback(true, null);
}
});
};
Then you can use your route /roomlist, to call the function getRoomlist when it gets hit and render the doc.
router.get('/roomlist', function(req, res){
programLogic(function(err, doc){
if(err){
console.log(err);
}
return res.send(doc);
});
});
If you still don't get it, just clone this and run through it
var programLogic = function (cb){
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
getRoomlist(db, function(err, doc) {
if(err){
console.log(err);
}
return cb(false, doc);
});
});
}// programLogic ends
var getRoomlist = function(db, callback) {
var cursor =db.collection('roomlist').find( );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
return callback(false, doc);
} else {
return callback(true, null);
}
});
};
router.get('/roomlist', function(req, res){
programLogic(function(err, doc){
if(err){
console.log(err);
}
return res.send(doc);
});
});
Which engine do you use for views rendering? Based on error message, property "roomname" has been interpreted as a partial, and cannot be found in views directory.