why mongodb in node express cannot set result to outside variable - javascript

So this question might be a javascript concept question. but I cannot figure out why
I retrieve data from mongodb however, I cannot define _res variable to become the result.
console.log(_res) will return undefined.
Does anyone know why? and how to make it work as it should be?
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm").find(query).toArray( function(err, result) {
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData
db.close();
res.render('index.ejs', {
vmData: vmData
});
});
});
console.log(_res)
});

Mongodb query is an asynchronous operation. The console statement is executed before the query has been processed.
You define _res outside which is undefined outside, so the same value is consoled outside.
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm")
.find(query)
.toArray((err, result){
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData
db.close();
console.log('Inside', _res) // <---Should give you correct result
res.render('index.ejs', {
vmData: vmData
});
});
});
console.log('Outside', _res);
});

The code is being executed asynchronously due to which when the console.log is executed the _res is undefined.
Try to execute your logic when the asyn methods are being executed.
app.route('/').get(function(req,res){
let _res;
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("vm");
var query = {};
dbo.collection("vm").find(query).toArray( function(err, result) {
if (err) throw err;
var vmData = JSON.stringify (result)
_res = vmData;
console.log(_res);
db.close();
res.render('index.ejs', {
vmData: vmData
});
});
});
});

Related

NodeJS Html-pdf: fs.readfilesync how to async/await

I have a problem with my html-pdf document creation. The problem is that often the code runs to fast to complete the process of pdf-docutment creation. The Processes consists out of building an HTML-String by replacing placeholders in an Html file. Below you see the code what happens afterwards.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
let html2 = fs.readFileSync(mergeFileRes, 'utf8');
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
if(html2){
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
} else {
}
}
});
My problem is that in many cases the html2 variable is not yet created before the pdf.create process starts. This is probably because the readFileSync takes too long to finish.
I was wondering, how can I fix this. How can I make the pdf.create wait for the readFileSync to finish and the html2 variable to be filled.
You can use fs.readFile to read the file asynchronously and html2 will be available within the callback function.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
fs.readFile(mergeFileRes, 'utf8', function(err, html2){
if (err) throw err;
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
});
}
});

How to Save data in multiple Collection using Mongodb and node js

I am using nodeJS and mongodb in one of my project.
I am trying to save data in multiple collection in one save button.
The code which I am using to achieve this is as follow:
var lastInsertId;
loginData={
userName: req.body.txtUsername,
password: req.body.txtPassword,
active:1,
createdOn:new Date(),
updatedOn:new Date()
};
var dbo = db.db("test");
dbo.collection("login").insertOne(loginData, function(err, result) {
if (err) throw err;
lastInsertId=result.insertedId;
});
if(lastInsertId){
usersData={
email: req.body.txtEmail,
firstName: req.body.txtFirstName,
lastName:req.body.txtLastName,
mobileNumber:req.body.txtMobileNumber,
login_id:lastInsertId,
active:1,
createdOn:new Date(),
updatedOn:new Date()
};
dbo.collection("users").insertOne(usersData, function(err, result) {
if (err) throw err;
console.log('saved to users');
});
}
Could you please tell what is wrong in the above code?
Thank you.
Regards,
Saloni
I want to give an explanation regarding the above issue with the code.
var lastInsertId; //it is undefined right now
//The following function is an asynchronous function.
var dbo = db.db("test");
dbo.collection("login").insertOne(loginData, function(err, result) {
if (err) throw err;
lastInsertId=result.insertedId;
});
/*NodeJs doesn't run synchronously. So, while it is running
above function i.e. insertOne, without it being completed it
reaches here.
Since, the above function is not completed
executing, lastInsertId will be undefined still.
So, the following block of code doesn't run */
if(lastInsertId){ //this block won't run
usersData={
//key-value pairs
};
dbo.collection("users").insertOne(usersData, function(err, result) {
if (err) throw err;
console.log('saved to users');
});
}
/*The solution to the above problem can be achieved by putting the
code block inside 'if(lastInsertId)' in callback of insert login.
So it would run only after the execution of insertOne function.*/
//Therefore the correct code would be:
var dbo = db.db("test");
dbo.collection("login").insertOne(loginData, function(err, result) {
if (err) throw err;
lastInsertId=result.insertedId;
if(lastInsertId){ //this block will run
usersData={
//key-value pairs
};
dbo.collection("users").insertOne(usersData, function(err, result) {
if (err) throw err;
console.log('saved to users');
});
}
});
I think move IF block inside callback of insert login function like this should work
var lastInsertId;
loginData = {
userName: req.body.txtUsername,
password: req.body.txtPassword,
active: 1,
createdOn: new Date(),
updatedOn: new Date()
};
var dbo = db.db("test");
dbo.collection("login").insertOne(loginData, function (err, result) {
if (err) throw err;
lastInsertId = result.insertedId;
if (lastInsertId) {
usersData = {
email: req.body.txtEmail,
firstName: req.body.txtFirstName,
lastName: req.body.txtLastName,
mobileNumber: req.body.txtMobileNumber,
login_id: lastInsertId,
active: 1,
createdOn: new Date(),
updatedOn: new Date()
};
dbo.collection("users").insertOne(usersData, function (err, result) {
if (err) throw err;
console.log('saved to users');
});
}
});

Mongodb find() return undefined

When ever I try to just use a simple find() for my mongodb it returns undefined.
var MongoClient = require('mongodb').MongoClient;
var url = 'mongodb://localhost:27017/local';
MongoClient.connect(url, function (err, db) {
db.collection('pokemon').find({ $search: { $text: 'Pikachu' } }).toArray(function(err, data){ console.log(data) })
});
EDIT:
Turns out I never created an index by putting
db.collection('pokemon').createIndex({Name: 'text'})
before all the code.
First of all, every time where you have:
function(err, data){ console.log(data) }
you should check errors:
function (err, data) {
if (err) {
console.log('Error:', err);
} else {
console.log('Data:', data);
}
}
Then you will probably see what's going on.
This is also true for the database connection itself - instead of:
MongoClient.connect(url, function (err, db) {
// use db here
});
you should handle errors:
MongoClient.connect(url, function (err, db) {
if (err) {
// handle errors
} else {
// use db here
}
});
If you don't handle errors then don't be surprised that you don't know why you don't get values.

Nodejs Mongoose Saving model undefined is not a function

I work with Nodejs Express routes and Mongoose to persist data.
I did the core routes CRUD operations with no problem. However, when I try to perform some operations on one of the fields of the Model and then try to save the Model with model.save it says about .save() method: "undefined is not a function"
So, here's the code.
The snippet number (1) works just fine:
router.put('/:myId', function (req, res, next) {
var ourUpdateData = req.body;
Model.findOne({myId: req.params.myId.toString()}, function (err, foundModel) {
if (err) throw err;
if (ourUpdateData.fieldA) foundModel.fieldA = ourUpdateData.fieldA;
if (ourUpdateData.fieldB) foundModel.fieldB = ourUpdateData.fieldB;
if (ourUpdateData.fieldC) foundModel.fieldC = ourUpdateData.fieldC;
if (ourUpdateData.fieldD) foundModel.fieldD = ourUpdateData.fieldD;
if (typeof ourUpdateData.fieldArray === "object") ourUpdateData.fieldArray = ourUpdateData.fieldArray;
foundModel.save(function (err, updatedModel) {
if (err) throw err;
res.send(updatedmodel);
});
});
});
So the Model has 6 fields: fieldA,..B,..C,..D, myId to identify as index and one field is Array of some values fieldArray. The example above saves the Model, works fine.
However if I now try to do something with array field fieldArray and then save the Model it throws me "undefined is not a function" when I use model.save() .
So the snippet (2) is the code that produces this error:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}, function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
So that thing above throws "undefined is not a function" on using model.save(.. )
I also tried second variant of the snippet (2), let's call it snippet (3), incorporating the .exec() Also doesn't work, throws the same "undefined is not a function" on model.save(.. )
So the snippet (3) is this:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
I'll be greatful for any inputs and suggestions!
Ansering to the attempt of Willson:
Yeah, I know when I call model.find(.. it gives array, if I call model.findOne(.. it gives one object json
I tried to simplify my example and in my version I actualy did use the:
"model[0].fieldArray = newFieldArray" to get the thing from Array fist (the array itself) and then assign to the new value.
The problem still persists, it gives me on model.save(.. "undefined is not a function " )
The current code is:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model[0].fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model[0].fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
This snippet (4) above gives on model.save(.. "undefined is not a function"
When you use in Mongoose the find method, it will return an array since it could discover one or many documents, so in your example you are querying to one specific element by its id, you should grab the first element on the returned array:
Model.find({myId: myId}).exec(function (err, documents) {
var model = documents[0];
if (err) throw err;
var fieldArray = model[0].fieldArray;
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost:27017/java-jedi');
var HackerSchema = new Schema({
name: String,
languages: [String]
});
var Hacker = mongoose.model('Hacker', HackerSchema);
// instantiating the model.
var oneHacker = new Hacker();
oneHacker.name = 'Richard Stallman';
oneHacker.save(function(err) {
if (err) throw err;
// finding the document intentionally for this example
Hacker.find({_id: oneHacker._id}, function(err, hackers) {
var hacker = hackers[0];
// modifying the document and updating it.
hacker.languages.push('Lisp');
hacker.save(function(err) {
if (err) throw err;
console.log(hacker);
});
});
});
OK guys!
I want to thank Wilson Balderrama, because he basically pointed to the right direction.
The code works! But let me clearify a bit.
Hacker.find({_id: oneHacker._id}, function(err, hackers) {
var hacker = hackers[0];
// modifying the document and updating it.
hacker.languages.push('Lisp');
hacker.save(function(err) {
if (err) throw err;
console.log(hacker);
});
});
So basically since the Model.find(.. returns an array
when we save we have to grab the thing from array before saving.
So corrected and final working version of my example will be:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.find({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model[0].fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model[0].fieldArray = newFieldArray;
model[0].save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
Or we can use just Model.findOne(.. to avoid confusing ourselves with this arry return
In this case we grab directly:
router.get('/:myId/:addThisToFieldArray', function(req, res, next) {
var myId = req.params.myId;
var addThisToFieldArray = req.params.addThisToFieldArray;
Model.findOne({myId: myId}).exec(function (err, model) {
if (err) throw err;
var fieldArray = model.fieldArray;
fieldArray.push("New thing to FieldArray");
var newFieldArray = fieldArray;
if (typeof newFieldArray === "object") model.fieldArray = newFieldArray;
model.save(function (err, updatedModel){
if (err) throw err;
res.send(updatedModel);
});
});
});
So in second case model[0].save(... becomes model.save(... direct grabbing and saving.
Thank you Wilson Balderrama again!!

How to wait for a response from a mongo findOne query in a node/express app before using the response in following control flow

I am new to node, and also JavaScript callbacks.
I am trying to check if an account exists in mongo and then 'save it' if it doesn't and return an error if it does.
I am currently trying to figure this out outside of my express app. This is what i have..
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (doc) {
if(doc) {
console.log('account exists');
} else {
console.log('good to go');
}
console.dir(doc);
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
if(err) throw err;
db.close();
callback();
});
}
with the console.dir(doc); above returning as undefined. How do I wait for the findOne to return before using the callback to console.log or save the account?
The reason you are getting undefined is because when you call your callback your are not passing it the doc. That line should look like callback(doc).
Here is an updated version of your code with a few suggestions:
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (err, doc) {
if(err) {
// something went wrong
console.log(err);
return;
}
if(doc) {
console.log('account exists');
console.dir(doc);
} else {
console.log('good to go');
}
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
db.close();
if(err) {
// don't use throw when in async code
// the convention is to call your callback with the error
// as the first argument (notice that I added an argument
// to the definition of your callback above)
callback(err);
}
else {
// call your callback with no error and the data
callback(null, doc);
}
});
}

Categories

Resources