Waterfall Node.js of Cannot read property 'Symbol(Symbol.toStringTag)' of undefined - node.js

I am writing async.waterfall in my biz. See code below. When I run the code, I got 'Cannot read property 'Symbol(Symbol.toStringTag)' of undefined', I do think I pass the right param.
function checkDeleteStatus(id) {
const idType = id instanceof Array;
const whereparam = idType ? [[id]] : [id];
let sql = `select status from ${bookingSheet} where id ${idType ? 'in' : '=' } ?`;
func.connPool(sql, whereparam, (err,rows,fields) => {
if(err == null){
let passTag = true;
for(var i = 0; i < rows.length; i++) {
let row = rows[i];
if (row.status == 0) {
passTag = false;
break;
}
}
return (callback)=>{
passTag ? callback(null, id) : callback('No', null);
}
} else {
return (callback)=>{
callback(err, null);
}
}
});
}
function deleteBooking(data, callback) {
let sql = `delete sql`;
func.connPool(sql, [data], (err,rows,fields) => {
if(err==null){
callback(null, data)
} else {
callback(err, null)
}
});
}
......
async.waterfall([checkDeleteStatus(id), deleteBooking], (err, result) => {
if (err) {
res.json({ code: 400, message: err.toString() })
} else {
res.json({ code: 200, message: "Query Successfully", data: result })
}
})
Interesting thing is, when I try to write below for checkDeleteStatus, it will run correctly. Is that mean, return part goes before sql part? I am new for using node.js waterfall, sorry for this kind of dumb question.
function checkDeleteStatus(id) {
const idType = id instanceof Array;
const whereparam = idType ? [[id]] : [id];
let sql = `select status from ${bookingSheet} `;
return (callback)=>{
callback(null, id);
}
}

I know the resone, the function should write like below. return (callback)=> should expend its range.
function checkDeleteStatus(id) {
return (callback)=>{
const idType = id instanceof Array;
const whereparam = idType ? [[id]] : [id];
let sql = `select status from ${bookingSheet} where id ${idType ? 'in' : '=' } ?`;
func.connPool(sql, whereparam, (err,rows,fields) => {
if(err == null){
let passTag = true;
for(var i = 0; i < rows.length; i++) {
let row = rows[i];
if (row.status == 0) {
passTag = false;
break;
}
}
passTag ? callback(null, id) : callback('No', null);
} else {
callback(err, null);
}
});}
}

Related

exports return null before executing mongodb save when i call it from another controller?

I have to call one controller function from another, but other function is not returning a proper value.
I called a function from one controller in line 'a',line 'b' is another controller.but inside forEach loop when it comes to line 'c', its not executing inside code instead it return null before executing the code from line 'd'.
a. var invoiceItemResp = InvoiceItemController.createInvoiceItems(itemList, doc.id);
b. exports.createInvoiceItems = (itemList, invoiceId) => {
var counter = 0;
var success = false;
itemList.forEach(element => {
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
c. invoiceItem.save((err, doc) => {
d. if(!err){
++counter;
if(counter == itemList.length){
response = {
"message": "success"
}
return response;
}
}else{
response = {
"message": "failed"
}
return response;
}
});
});
}
Your needs the loop to be async and wait for DB to write,
const invoiceItemResp = await InvoiceItemController.createInvoiceItems(itemList, doc.id);
exports.createInvoiceItems = async (itemList, invoiceId) =>
{
var counter = 0;
var success = false;
let resposneArray = [];
let response= {};
try
{
for (const element of itemList)
{
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
const err = await invoiceItem.save();
if (!err)
{
++counter;
if (counter == itemList.length)
{
response = {
"message": "success"
};
resposneArray.push(response);
}
} else
{
response = {
"message": "failed"
};
resposneArray.push(response)
}
});
return resposneArray;
}
catch (e)
{
throw e;
}
};
You should use async await while writing to db.
var invoiceItemResp = await InvoiceItemController.createInvoiceItems(itemList, doc.id);
exports.createInvoiceItems = async (itemList, invoiceId) => {
var counter = 0;
var success = false;
itemList.forEach(element => {
var invoiceItem = new InvoiceItem({
_id: new mongoose.Types.ObjectId(),
invoice_id: invoiceId,
item: element.item,
amount: element.amount
});
invoiceItem.save((err, doc) => {
if(!err){
++counter;
if(counter == itemList.length){
response = {
"message": "success"
}
return response;
}
}else{
response = {
"message": "failed"
}
return response;
}
});
});
}

How to await on class constructor in Node js

I have two classes as below
class AClient
class AClient {
constructor(AHeaderObj) {
logger.info("inside tenant client constructor");
this.tenant_uri = tenantHeaderObj.tenant_uri || config.TENANT_URI;
this.refresh_token = tenantHeaderObj.refresh_token;
this.tenant_header = tenantHeaderObj.tenant_header;
}
Class BClient
class BClient {
constructor(b_client) {
logger.info("Inside mongoClient/constructor ");
this.tenant_client = tenant_client;
}
async find(db_name, collection_name, selectorQuery) {
try {
logger.info("Inside mongoClient find records");
let dbName = await getDB(db_name, this.tenant_client);
let db = await getConnection(dbName, this.tenant_client);
logger.info("selectorQuery"+JSON.stringify(selectorQuery));
let doc = db.collection(collection_name).find(selectorQuery).toArray();
logger.info("****************doc**********"+JSON.stringify(doc));
return await promiseWrapper(null, doc);
} catch (err) {
logger.info("Caught error in mongoClient find records ", err);
return await promiseWrapper(err, null);
}
}
async findSome(db_name, collection_name, query, projection, sort, limit){
logger.info("Inside mongoClient findSome records");
try{
let dbName = await gettDB(db_name, this.tenant_client);
let db = await getConnection(dbName, this.tenant_client);
var selector = [{ $match : query},
{ $project : projection},
{ $sort : sort}];
if(limit > 0){
selector.push({ $limit : limit})
}
let docs = db.collection(collection_name).aggregate(selector).toArray();
return await promiseWrapper(null, docs);
} catch (err) {
logger.info("Caught error in mongoClient findSome records ", err);
return await promiseWrapper(err, null);
}
}
Now I am using it in below 2 ways . One way it works another it is not.
Case1: When it is not working
var searchAll = function (type, text, sortBy, sort, Code, AHeaderObj) {
logger.info("Inside searchAll function.");
var selector = mongoQuery.searchAll(type, text, sortBy, sort, Code);
var AObj = new AClient(AHeaderObj);
logger.info("123");
var mongoObj = new BClient(AObj);
logger.info("1235");
var findSome = callbackify(mongoObj.findSome)
logger.info("12356");
return new Promise((resolve1, reject1) => {
logger.info("123567");
findSome(dBName, collectionName, selector.query, selector.projection, selector.sort, 999999999, function (err1, res1) {
if (err1) {
logger.error("Failed to find");
reject1(err1);
} else {
logger.info("Successfully found");
resolve1(res1)
}
});
})
}
Case2: Where it is working as charm.
var getId = function (id, headerObj, callback) {
logger.info("inside getAccountById() START:");
let selector = mongoQuery.GetAccByIdQueryWithIdModelVersion("Id", id, “version", "v2.1")
let index = 0;
var AObj = new AClient(AHeaderObj);
logger.info("123");
var mongoObj = new BClient(AObj);
logger.info("1235");
mongoObj.find(dBName, collectionName, selector).then((result) => {
logger.info("123568");
if (result && result.length > 0) {
logger.info("a");
logger.info("Found an with id: " + id);
if (result[index].credentials.length > 0) {
logger.info("getById() END:"+JSON.stringify(result));
callback(null, result);
}else {
logger.info("b");
let error = {
"message": "Unable to fetch the with id: " + id
};
logger.warn(error.message);
logger.info("getById() END:");
callback(error, null);
}
}).catch((err) => {
logger.info("c");
logger.info("error" + JSON.stringify(err));
callback(err, null);
});
}
Can someone help what am I doing wrong in Case1 . I observed that ion Case 1 object creation is not awaited and db function is been called where I get below error.
Caught error in mongoClient findSome records TypeError: Cannot read property 'tenant_client' of undefined
Instead of trying to await on class initialization, make the constructor empty and provide and async init method which does the same thing as what the constructor would do.
Make sure that other methods check if the object has been instantiated via the init method and throw an error if not :)

Paging query with NodeJS and ObjectionJs

Hi I am relatively new to NodeJS and am using ObjectionJS as ORM.
I want to do a migration script for my users table, in order to change some field of each row.
I make something like this
export default class UserMigration {
constructor(firstId, lastId = 9000000) {
this.firstId = firstId;
this.lastId = lastId;
}
migrate() {
let more = true;
let page = 0;
let batchSize = 100;
while(more) {
UserModel.query().where('id', '>=', this.firstId)
.where('id', '<=', this.lastId)
.page(page, batchSize)
.then((result) => {
let users = result.results;
debug('Page: ', page);
debug('PageSize: ', users.length)
users.forEach((user) => {
// Do something here
});
if(result.results.length < batchSize) {
more = false
} else {
page++;
}
})
}
}
}
But then I realize that the query is being executed asynchronously while the while block is being executed synchronously, is that correct?
How can I achieve the migration without making one big query that returns all the users at once?
Thanks in advance!!
I have achieved that using async/await
export default class UserMigration {
constructor(firstId, lastId = 9000000) {
this.firstId = firstId;
this.lastId = lastId;
}
run() {
this.migrateV3().then((data) => {
debug('All migrated');
debug('data: ', data);
}).catch((data) => {
debug('Error');
debug('data: ', data);
});
}
async migrateV3() {
let more = true;
let page = 0;
let batchSize = 100;
while(more) {
try {
let result = await UserModel.query().where('id', '>=', this.firstId)
.where('id', '<=', this.lastId)
.page(page, batchSize);
let users = result.results;
debug('Page: ', page);
debug('PageSize: ', users.length)
for(let user of users) {
debug(`User ${user.id} migration start`);
// Do something
};
if(result.results.length < batchSize) {
more = false
} else {
page++;
}
}
catch (err) {
throw err;
}
}
}
}

node.js using callback on class functions

I want to return value to varibales so I tried to write it like that using return but that did't work
class move {
getLastMove(id){
var MoveRequest = "SELECT * FROM users ORDER BY id";
var query = connection.query(MoveRequest, function(err,rows, result) {
//console.log('rows', rows.length);
if (rows.length == 0) { // evaluate the count
return ("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
}
if (rows.length > 0) {
for (var i in rows) {
console.log('getLastMove',id);
var move = rows[i].MoveString;
if (rows[i].GameId == id){
return move;
}
}
}
//console.log("Total Records:- " + result[0].total);
});
var move="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
return move;
}
};
so I tried to use callback like that
class move {
getLastMove(id){
var MoveRequest = "SELECT * FROM users ORDER BY id";
var query = connection.query(MoveRequest, function(err,rows, result,callback) {
//console.log('rows', rows.length);
if (rows.length == 0) { // evaluate the count
callback ("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
}
if (rows.length > 0) {
for (var i in rows) {
console.log('getLastMove',id);
var move = rows[i].MoveString;
if (rows[i].GameId == id){
callback(move);
}
}
}
//console.log("Total Records:- " + result[0].total);
});
var move="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
callback(move);
}
};
but when run callback example i get this error
TypeError: callback is not a function
class move {
getLastMove(id,callback){
var query = connection.query(MoveRequest, function(err,rows, result) {
//do some operation then
if (rows.length > 0) {
for (var i in rows) {
console.log('getLastMove',id);
var move = rows[i].MoveString;
if (rows[i].GameId == id){
callback(err,move) //<-------
}
}
}
});
}
};
var moveInstance = new move();
moveInstance.getLastMove(id,function(err,result){ //code here })
You're using callback in a wrong way. Pass a callback to getLastMove() :
class move {
getLastMove(id, callback){
var MoveRequest = "SELECT * FROM users ORDER BY id";
var query = connection.query(MoveRequest, function(err,rows, result) {
if(err) {
return callback(err)
}
if (rows.length == 0) { // evaluate the count
return callback (null, "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
}
if (rows.length > 0) {
for (var i in rows) {
if (rows[i].GameId == id){
callback(null, rows[i].MoveString);
}
}
}
});
}
};
Suppose moveObj is an object of type move, call the function getLastMove like:
var moveObj = new move();
moveObj.getLastMove(34, function (err, data) { // 34 is the value of `id`
if(err) {
// There was some error in execution of getLastMove; var `err` has info regarading that.
return console.log("There was some err while executing getLastMove", err);
}
// If no Error, process your `data` accordingly
console.log("Data returned by callback", data);
});

How to send a response only after a query has been executed in loopback

I have a remote method in loopback like:
Alerts.getAlertDetails = function (alertId, options, cb) {
var response = {};
var userId = options.accessToken.userId;
Alerts.app.models.MobileUserAlertRelation.find({where: {userId: userId, alertId: alertId, isDeleted: -1}, include: {relation: 'alerts', scope: {include: ['alertTypes'], where: {status: 1}}}}, function (err, alertRel) {
if (alertRel.length > 0 && alertRel[0].alerts()) {
response.code = 200;
response.status = "success";
response.data = {};
if (alertRel[0].alertId) {
response.data.alertId = alertRel[0].alertId;
}
if (alertRel[0].readStatus) {
response.data.readStatus = alertRel[0].readStatus;
}
if (alertRel[0].receivedOn) {
response.data.alertReceivedOn = alertRel[0].receivedOn;
}
var alertData = alertRel[0].alerts();
if (alertData.title) {
response.data.alertTitle = alertData.title;
}
if (alertData.message) {
response.data.alertShortMessage = alertData.message;
}
if (alertData.extraMessage) {
response.data.alertMessage = alertData.extraMessage;
}
if (alertData.priority) {
response.data.alertPriority = alertData.priority;
}
if (alertData.validUntil) {
response.data.alertExpiresOn = alertData.validUntil;
}
if (alertData.images && alertData.images.length > 0) {
response.data.alertImages = [];
for (var image in alertData.images) {
if (alertData.images.hasOwnProperty(image)) {
response.data.alertImages.push(constants.ALERT_IMAGE_URL + '/' + alertData.images[image]);
}
}
}
if (alertData.alertTypes() && alertData.alertTypes().alertTypeName) {
response.data.alertType = alertData.alertTypes().alertTypeName;
}
if (alertData.alertLocations && alertData.alertLocations > 0) {
response.data.alertLocations = [];
response.data.policeDepartments = [];
response.data.hospitals = [];
response.data.fireDepartments = [];
var locations = alertData.alertLocations;
for (var locKey in locations) {
if (locations.hasOwnProperty(locKey)) {
if (locations[locKey].data) {
response.data.alertLocations.push(locations[locKey].data);
console.log(locations[locKey].data);
if (locations[locKey].data.type) {
var locationType = locations[locKey].data.type;
if (locationType === "Polygon") {
var coordinates = locations[locKey].data.coordinates[0];
var polygonCenter = getPolygonCenter(coordinates);
console.log(polygonCenter);
}
}
}
}
}
}
cb(null, response);
} else {
response.code = 404;
response.status = 'error';
response.message = 'Alert not found.';
cb(null, response);
}
})
};
But when I call this method through api, response is received without data added from the complex code part. I know that callback will be called asynchronously here and so that cb(response) will be called before the complex code is executed completely. How can i send response only after the complex part is completed and data is correctly added to response from that data. I cannot move cb(response) inside the complex part as data is being pushed in for loop.
I have heard of promises, can it be used here, if so, how could it be done?
Someone please help!!
The problem is because of fetching relation in if.
The relation method is an async.
Alerts.getAlertDetails = function (alertId, options, cb) {
var response = {};
var userId = options.accessToken.userId;
Alerts.app.models.MobileUserAlertRelation.find({where: {userId: userId, alertId: alertId, isDeleted: -1}, include: {relation: 'alerts', scope: {include: ['alertTypes'], where: {status: 1}}}}, function (err, alertRel) {
if(alertRel.length < 1){
return handleError();
}
alertRel[0].alerts(handleResponse);
function handleResponse(err, alertRelAlert){
if(err) return handleError();
if (alertRelAlert) {
//all that code in question if if section
}else {
return handleError();
}
}
function handleError(){
response.code = 404;
response.status = 'error';
response.message = 'Alert not found.';
cb(null, response);
}
});
}

Resources