Node js - How access another function in same controller - javascript

I have two functions and i can't access from function 2 to function 1.
How can i do that?
class firstController
{
one(req, res)
{
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
Promise.all([stamp]).then(function(listOfResults)
{
var data = listOfResults[0][0].stamp;
res.send(data);
}).catch(function(err)
{
// ... query error checks
console.log(err);
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
}
module.exports = firstController;
i have this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'getStamp' of undefined
Thank you

Use this to access functions within the same class in ES6. This is quite complex in ES5 and ES6 compared to other languages and I recommend you have a look at it.
class firstController
{
one(req, res)
{
res.send("hello");
}
two(req, res){
this.one(req, res);
}
}
module.exports = firstController;
UPDATE
To get the data from one into two you'll need to return the result of the Promise like this
one(req, res) {
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
return Promise.all([stamp]).then(function(listOfResults) {
return listOfResults[0][0].stamp;
}).catch(function(err) {
// ... query error checks
console.log(err);
return err;
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
Only use res.send when you want to return data to the client

Related

NodeJS ASync call of MongoClient GetData routine

The code below is a mix of https://www.w3schools.com/nodejs/nodejs_mongodb_find.asp
and
https://stackoverflow.com/questions/49982058/how-to-call-an-async-function#:~:text=Putting%20the%20async%20keyword%20before,a%20promise%20to%20be%20resolved.
When you look at the console.log below the code, things seem to be running out of order. I thought by making the function async and using the .then I would avoid those issues.
I want the MongoDB data retrieval function separate from the app.get function.
No data is being returned to the get request. I guess the app.get code is falling through and ending before the function returns the value. What do I need to correct?
async function getLanguageTranslationData(fromLanguage, toLanguage) {
console.log("Started getLanguageTranslationData")
const databaseUrl = "mongodb://localhost:27017"
const databaseName = 'MyCompanyPOC'
mongoClient.connect(databaseUrl, function(err, conn) {
if (err) throw err;
const collectionName = "Phrases";
var dbo = conn.db(databaseName)
var query =
{ $and:
[ {masterLanguage: fromLanguage},
{localizedLanguage: toLanguage}
]
}
console.log("query=" + JSON.stringify(query));
console.log("about to retrieve data");
dbo.collection(collectionName).find(query).toArray(
function(err, result) {
if (err) throw err;
console.log("Back from mongoDB.find()")
console.log(JSON.stringify(result))
return result
conn.close()
})
})
}
app.get("/api/gettranslations/:fromLanguage/:toLanguage",
async function(req, res) {
console.log("Backend: /api/gettranslations method started: " +
" fromLanguage=" + req.params.fromLanguage +
" toLanguage=" + req.params.toLanguage)
getLanguageTranslationData(
req.params.fromLanguage,
req.params.toLanguage)
.then((arrayResult) => {
console.log("got arrayResult back from getLanguageTranslationData")
res.status(200).json(arrayResult)
console.log("Backend: End of /api/gettranslations process")
})
})
Node.JS Console output:
listening on port 3001
Backend: /api/gettranslations method started: fromLanguage=en-US toLanguage=es-MX
Started getLanguageTranslationData
(node:44572) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
got arrayResult back from getLanguageTranslationData
Backend: End of /api/gettranslations process
query={"$and":[{"masterLanguage":"en-US"},{"localizedLanguage":"es-MX"}]}
about to retrieve data
Back from mongoDB.find()
[{"_id":"5f403f7e5036d7bdb0adcd09","masterLanguage":"en-US","masterPhrase":"Customers","localizedLanguage":"es-MX","localizedPhrase":"Clientes"},{ etc...
The thing is getLanguageTranslationData should return a promise so that you can use it as a promise in your handler, but in your case, call to getLanguageTranslationData will return undefined as all the code inside this function will execute asynchronously due to nodejs non-blocking nature.
So what you can do is return promise from your getLanguageTranslationData function like this.
function getLanguageTranslationData(fromLanguage, toLanguage) {
const databaseUrl = "mongodb://localhost:27017"
const databaseName = 'MyCompanyPOC'
return new Promise((resolve, reject)=>{
mongoClient.connect(databaseUrl, function(err, conn) {
if (err) reject(err);
else{
const collectionName = "Phrases";
var dbo = conn.db(databaseName)
var query =
{ $and:
[ {masterLanguage: fromLanguage},
{localizedLanguage: toLanguage}
]
}
dbo.collection(collectionName).find(query).toArray(
function(err, result) {
if (err) reject(err);
else
resolve(result);
})
}
})
})
}
and then use await in your handler to use that promise returned
app.get("/api/gettranslations/:fromLanguage/:toLanguage",
async function(req, res) {
try{
let arrayResult = await getLanguageTranslationData(req.params.fromLanguage, req.params.toLanguage);
res.status(200).json(arrayResult)
}catch(err){
// return error
}
})
The above code will give you the gist of what you need to do, actual code may vary according to your needs.
You can refer async-await from here
I got it working in this way, based on this example: Node.js, Mongo find and return data
#Namar's answer is probably correct too, but I was testing this the same time he posted. As the StackOverflow question/answer above notes, the up-to-date versions of MongoClient have support for promises. That post also shows how to put in a separate module, which is something I will probably do later this week.
function getLanguageTranslationData(fromLanguage, toLanguage) {
console.log("Started getLanguageTranslationData")
const databaseUrl = "mongodb://localhost:27017"
const databaseName = 'ShedCompanyPOC'
return mongoClient.connect(databaseUrl)
.then(function(conn) {
var collectionName = "UploadedDataeFromExcel";
var dbo = conn.db(databaseName)
var query =
{ $and:
[ {masterLanguage: fromLanguage},
{localizedLanguage: toLanguage}
]
}
console.log("query=" + JSON.stringify(query));
console.log("about to retrieve data");
var collection = dbo.collection(collectionName)
return collection.find(query).toArray();
}).then(function(result) {
console.log("Back from mongoDB.find()")
console.log(JSON.stringify(result))
//conn.close()
return result
});
}
app.get("/api/gettranslations/:fromLanguage/:toLanguage",
async function(req, res) {
console.log("Backend: /api/gettranslations method started: " +
" fromLanguage=" + req.params.fromLanguage +
" toLanguage=" + req.params.toLanguage)
getLanguageTranslationData(
req.params.fromLanguage,
req.params.toLanguage)
.then(function(arrayResult) {
console.log("got arrayResult back from getLanguageTranslationData")
res.status(200).json(arrayResult)
console.log("Backend: End of /api/gettranslations process")
}, function(err) {
console.log("The promise was rejected", err, err.stack)
})
})

Calling several functions as promises get Error: Can't set headers after they are sent

I tried to write this code very simple to focus on solving the problem, but what I really want is for one nodejs controller to call another more advanced nodejs controller multiple times.
This is my Route
// test Route
var express = require('express');
var router = express.Router();
var testController = require('../controllers/testController');
router.get('/getTest', function(req, res) {
testController.getTest(req, res);
});
module.exports = router;
This is my testController.js
exports.getTest = function(req, res) {
var myArray = [300,200,400,100,500];
var myResult = [];
// Find all data based on myArrau
var findData = function() {
return new Promise((resolve, reject) => {
for (var i=0; i<myArray.length; i++) {
callDataController(i, myArray[i]);
}
resolve();
})};
// Call and get the specific data
var dataController = require('./dataController');
var callDataController = function(i, myValue) {
return new Promise((resolve, reject) => {
dataController.getData (
{ "myValue": myValue }, res,
function(err, data) {
if (!err) {
myResult[i] = data;
resolve(data);
} else {
reject(new Error('ERR dataController: ' + err));
};
});
})};
// Send result to page
var sendResult = function(data) {
return new Promise((resolve, reject) => {
res.json({error:false, "myResult":myResult})
resolve();
});
};
// Run promises
findData()
.then(sendResult)
.catch(err => {
console.log("getTest ERR: " + err);
res.json({error:true,err})
}
)
}
And this is my dataController which usually do a lot of mongodb work
exports.getData = function(req, res) {
console.log("Data received: " + JSON.stringify(req, null, 4));
console.log("Doing lots of mongodb work taking milliseconds to minutes")
setTimeout(function(){},req.myValue);
res.json({error:false, "myValue":req.myValue+1000 })
}
And here comes the problem, best explained by the terminal console.log
Data received: {
"myValue": 300
}
Do a LOT of mongodb work taking anywhere from milliseconds to minutes
Data received: {
"myValue": 200
}
Do a LOT of mongodb work taking anywhere from milliseconds to minutes
Data received: {
"myValue": 400
}
Do a LOT of mongodb work taking anywhere from milliseconds to minutes
Data received: {
"myValue": 100
}
Do a LOT of mongodb work taking anywhere from milliseconds to minutes
Data received: {
"myValue": 500
}
Do a LOT of mongodb work taking anywhere from milliseconds to minutes
GET /testRoute/getTest 304 8.448 ms - -
getTest ERR: Error: Can't set headers after they are sent.
(node:9976) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
(node:9976) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: Can't set headers after they are sent.
(node:9976) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): Error: Can't set headers after they are sent.
(node:9976) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: Can't set headers after they are sent.
(node:9976) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): Error: Can't set headers after they are sent.
Even if I only put one value in myArray I still get the Error: Can't set headers after they are sent.
This is the one point of async which I just cant get to work.
(already tried adding them all to a Promise.all array, same problem)
Your problem is that the controller that you're calling multiple times is writing the response to the client - multiple times (or at least, it's trying to). Instead, let it just return a promise, and respond only in the router code:
// test Route
var express = require('express');
var router = express.Router();
var testController = require('../controllers/testController');
router.get('/getTest', function(req, res) {
testController.getTest(req).then(function sendResult(myResult) {
res.json({error:false, "myResult":myResult}))
}, err => {
console.log("getTest ERR: " + err);
res.json({error:true,err});
});
});
module.exports = router;
// testController.js
var dataController = require('./dataController');
exports.getTest = function(req) {
var myArray = [300,200,400,100,500];
var myResult = [];
// Find all data based on myArrau
function findData() {
return myArray.map(callDataController);
}
// Call and get the specific data
function callDataController(myValue, i) {
return dataController.getData (
{ "myValue": myValue }
).catch(function(err) {
throw new Error('ERR dataController: ' + err)
});
};
// Run promises
return Promise.all(findData());
}
// dataController
exports.getData = function(req) {
return new Promise((resolve, reject) => {
console.log("Data received: " + JSON.stringify(req, null, 4));
console.log("Doing lots of mongodb work taking milliseconds to minutes")
setTimeout(function(){
resolve({error:false, "myValue":req.myValue+1000 });
}, req.myValue);
});
};

How can I extract the result of mongoose call and pass it into a variable

I tried getting it out by making it into a function and passed return, and failed in doing so.
I saw an example where someone used module.exports.VariableName = objects;
My issue is I still can't access or use that VariableName. e.g. var names = Collection; on the same file.
ReferenceError: Collection is not defined
What am I doing wrong? Thank you.
mongoose.connection.on('open', function(ref) {
console.log('Connected to mongo server.');
//trying to get collection names
mongoose.connection.db.listCollections().toArray(function(err, names) {
if (err) {
console.log(err);
} else {
module.exports.Collection = names;
}
});
});
The problem is that you are assigning to module.exports a result of an async operation. This means you are most likely assigning this data after you are accessing it with require().
By considering only the provided code, one way to solve this would be to wrap your code into a promise that resolves with the names:
module.exports = function(mongoose) {
return new Promise(function(resolve, reject) {
mongoose.connection.on('open', function (ref) {
console.log('Connected to mongo server.');
//trying to get collection names
mongoose.connection.db.listCollections().toArray(function(err, names) {
if (err) {
reject(err);
}
else {
resolve(names);
}
});
});
});
}
And then use it like:
require('PATH_TO_CODE_ABOVE')(mongoose).then(function(collection) {
console.log(collection); // This logs the names collection
}, function(err) {
console.log(err); // this will log an error, if it happens
});

javascript instance method not found: Object #<Object> has no method 'handleRequest' [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
the following code works:
Experimenters = function(db)
{
Object.apply(this, arguments);
this.db = db;
};
util.inherits(Experimenters, Object);
Experimenters.prototype.getAll = function(req, res)
{
return this.db.Experimenter.getAllExperimentersWithExperiments()
.then(function(exptrs) {
res.json(200, exptrs);
})
.catch(function(error) {
res.json(500, error);
});
};
however the code for each of my request handlers is pretty much all the same, so I thought I'd reduce duplicate code by creating a generic request handler:
Experimenters.prototype.handleRequest = function(promise, res)
{
return promise
.then(function(success){
res.json(200, success);
})
.catch(function(error) {
if (error instanceof dbErrors.NotFoundError) {
res.json(404, error);
} else if ((error instanceof dbErrors.ValidationError) ||
(error instanceof dbErrors.UniqueConstraintError)) {
res.json(422, error);
} else {
// unknown error
console.error(error);
res.json(500, error);
}
});
};
And modify my request handlers like this:
Experimenters.prototype.getAll = function(req, res)
{
this.handleRequest(
this.db.Experimenter.getAllExperimentersWithExperiments(),
res);
};
But I'm getting:
TypeError: Object #<Object> has no method 'handleRequest'
the code is called via my routes/index.js
// edited for brevity
var Experimenters = require("../controllers/experimenters");
module.exports.initialize = function(app)
{
var exptrs = new Experimenters(app.db);
app.get("/api/experimenters", exptrs.getAll);
};
which is called from my app.js:
//edited for brevity
var config = require(path.join(__dirname, "..", "config")),
createDB = require(path.join(__dirname, "models")),
routes = require(path.join(__dirname, "routes"));
var db = createDB(config);
app.set("db", db);
// edited for brevity
routes.initialize(app);
Updates:
you are getting this error because you should be binding exptrs to the function like this:
app.get("/api/experimenters", exptrs.getAll.bind(exptrs));
This is because you are passing the function exptrs.getAll as a parameter into the .get function which is called by app and therefore this in exptrs.getAll will be referring to app.
So another solution is to pass an anonymous function to get:
app.get("/api/experimenters", function(){exptrs.getAll()});
Normally when you get errors like Object #<Object> has no method 'handleRequest',
it either means
.prototype.handleRequest() is not defined properly, or
the object that is calling .handleRequest() is not actually the
correct object.
I believe in the return of .handleRequest it should be promise().then(...).catch(...), instead of promise.then(...).catch(...), because just having promise without () you are not calling the function.
Similar to
var b = function(){
return 1
};
function a(c){
return c
}
var d = a(b);
console.log(d);
//it will not log 1, unless
//function a(c){
// return c()
//}
And in .getAll you should be returning this.handleRequest(..) too, rather than just calling it.
I was able to solve this the following way:
First, I noticed that my handleRequest() made no use of 'this', so it could be a simple function
Secondly, I modified handleRequest() by adding a Promise.try() around the promise
handleRequest = function(promise, res)
{
return Promise.try(function(){
return promise;
})
.then(function(success){
res.json(200, success);
})
.catch(function(error) {
if (error instanceof dbErrors.NotFoundError) {
res.json(404, error);
} else if ((error instanceof dbErrors.ValidationError) ||
(error instanceof dbErrors.UniqueConstraintError)) {
res.json(422, error);
} else {
// unknown error
console.error(error);
res.json(500, error);
}
});
};

Set Variable to result of Mongoose Find

I'm trying to do something like this
function retrieveUser(uname) {
var user = User.find({uname: uname}, function(err, users) {
if(err)
console.log(err);
return null;
else
return users[0];
return user;
But this returns a document instead of a user object. The parameter users is an array of user objects matching the query, so how would I store one of the objects into a variable that my function could return?
The function User.find() is an asynchronous function, so you can't use a return value to get a resultant value. Instead, use a callback:
function retrieveUser(uname, callback) {
User.find({uname: uname}, function(err, users) {
if (err) {
callback(err, null);
} else {
callback(null, users[0]);
}
});
};
The function would then be used like this:
retrieveUser(uname, function(err, user) {
if (err) {
console.log(err);
}
// do something with user
});
Updated on 25th Sept. 2019
Promise chaining can also be used for better readability:
Model
.findOne({})
.exec()
.then((result) => {
// ... rest of the code
return Model2.findOne({}).exec();
})
.then((resultOfModel2FindOne) => {
// ... rest of the code
})
.catch((error) => {
// ... error handling
});
I was looking for an answer to the same question.
Hopefully, MongooseJS has released v5.1.4 as of now.
Model.find({property: value}).exec() returns a promise.
it will resolve to an object if you use it in the following manner:
const findObject = (value) => {
return Model.find({property: value}).exec();
}
mainFunction = async => {
const object = await findObject(value);
console.log(object); // or anything else as per your wish
}
Basically, MongoDB and NodeJS have asynchronous functions so we have to make it to synchronous functions then after it will work properly as expected.
router.get('/', async function(req, res, next) {
var users = new mdl_users();
var userData = []; // Created Empty Array
await mdl_users.find({}, function(err, data) {
data.forEach(function(value) {
userData.push(value);
});
});
res.send(userData);
});
In Example, mdl_users is mongoose model and I have a user collection(table) for user's data in MongoDB database and that data storing on "userData" variable to display it.In this find function i have split all documents(rows of table) by function if you want just all record then use direct find() function as following code.
router.get('/', async function(req, res, next) {
var users = new mdl_users();
var userData = await mdl_users.find();
res.send(userData);
});

Categories