Node JS for loop inserting data twice - node.js

I am trying import the contacts in a database but sometime its inserting records 2 times. Requirement is, If the number is already exist it should get updated otherwise inserted as a new row. I am using MySQL database.
I am using for loop with async.
var numbers = {
numbers:[
{
name:"A",
number:9876543211
},
{
name:"B",
number:7876543211
},
{
name:"C",
number:9886543211
},
{
name:"D",
number:8876543211
}
]
};
async.forEachOf(numbers, (numberObj, key, callback) => {
var createdAt = moment.utc().valueOf();
var updatedAt = moment.utc().valueOf();
gfs.checkContact(userInfo.user_id, code, numberObj.number, function(contactInfo, err){
if(err){
response.error = "sorry";
res.send(response); return false;
}else{
if (contactInfo.length > 0) {
gfs.qry("UPDATE contacts SET fullName='"+numberObj.name+"', updatedAt='"+updatedAt+"' WHERE cid='"+contactInfo[0].cid+"'").then(function (results){
}).catch(function (errorMessage){
})
}else{
gfs.qry("INSERT INTO contacts(user_id, fullName, code, mobile, createdAt, updatedAt) VALUES('"+userInfo.user_id+"', '"+numberObj.name+"', '"+code+"', '"+numberObj.number+"', '"+createdAt+"', '"+updatedAt+"')").then(function (results){
}).catch(function (errorMessage){
})
}
}
callback();
});
}, err => {
if (err){
response.error = "sorry";
res.send(response);
}else{
response.success = "success";
response.numbers = numbers;
res.send(response);
}
});
I want to insert the contact number if it's not exist in the database for logged-in user id or it should get update the other fields like name, updated at if number already in database for the logged-in user id.

The callback needs to be inside the .thens or .catches.
async.forEachOf(numbers, (numberObj, key, callback) => {
var createdAt = moment.utc().valueOf();
var updatedAt = moment.utc().valueOf();
gfs.checkContact(userInfo.user_id, code, numberObj.number, function (contactInfo, err) {
if (err) {
return callback(err);
} else {
if (contactInfo.length > 0) {
gfs.qry("UPDATE contacts SET fullName='" + numberObj.name + "', updatedAt='" + updatedAt + "' WHERE cid='" + contactInfo[0].cid + "'")
.then(function (results) {
return callback(null, true);
}).catch(function (errorMessage) {
return callback(errorMessage);
})
} else {
gfs.qry("INSERT INTO contacts(user_id, fullName, code, mobile, createdAt, updatedAt) VALUES('" + userInfo.user_id + "', '" + numberObj.name + "', '" + code + "', '" + numberObj.number + "', '" + createdAt + "', '" + updatedAt + "')")
.then(function (results) {
return callback(null, true);
}).catch(function (errorMessage) {
return callback(errorMessage);
})
}
}
});
}, err => {
if (err) {
response.error = "sorry";
res.send(response);
} else {
response.success = "success";
response.numbers = numbers;
res.send(response);
}
});
Note: in your function gfs.checkContact the callback signature is (contactInfo, err). Which is reverse of what Node.js standard. Node uses err, callback or err, data.
EDIT1:
Also, .forEachOf iterates object like Object.keys. In your case there is only one key called numbers.
So, the numberObj will contain:
[ { name: 'A', number: 9876543211 },
{ name: 'B', number: 7876543211 },
{ name: 'C', number: 9886543211 },
{ name: 'D', number: 8876543211 } ]
And numberObj.name will be undefined.
You probably want
async.each(numbers.numbers, ...)

I have changed my code, now using promise. It's working fine now.
var numbers = [
{
name:"A",
number:9876543211
},
{
name:"B",
number:7876543211
},
{
name:"C",
number:9886543211
},
{
name:"D",
number:8876543211
}
];
async.forEachOf(numbers, (numberObj, key, callback) => {
var createdAt = moment.utc().valueOf();
var updatedAt = moment.utc().valueOf();
gfs.checkContactPromise({
user_id:userInfo.user_id,
code:code,
mobile:numberObj.number,
fullName:numberObj.name,
createdAt:createdAt,
updatedAt:updatedAt
}).then( function (addContactQry){
gfs.qry(addContactQry).then(function (results){
userContacts.push("'"+numberObj.number+"'");
callback();
}).catch(function (errorMessage){
callback();
})
}).catch( function (errorMessage){
callback();
});
}, err => {
if (err){
response.error = "sorry";
res.send(response);
}else{
response.success = "success";
response.numbers = numbers;
res.send(response);
}
});

Related

Can't I use the req.user inside promises in nodejs?

I am trying to do the stripe payment using nodejs and I am getting the following errors. One in console and one in web app UI in the browser. What are the reasons?
Also I am trying to use req.user property details which are saved in mongoDB.
I am getting the console error as : (node:6344) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'subscriptionPlan' of undefined
and on browser =>
Error: You cannot use a Stripe token more than once: tok_1IJggu*******************.
Below is my code:
router.post('/processPayment/:priceID', (req, res) => {
console.log("plan Token = "+ req.body.stripeToken);
console.log("plan Email = "+ req.body.stripeEmail);
var dateFormated, dateFormated2;
return stripe2.customers.create({
source: req.body.stripeToken,
email: req.body.stripeEmail
}).then(customer => {
stripe2.subscriptions.create({
customer: customer.id,
items: [
{
plan: req.params.priceID
}
]
}).then(subscription => {
console.log("subscription.status = "+ subscription.status);
dateFormated = new Date();
dateFormated2 = new Date();
console.log(dateFormated2.getMinutes() +' '+dateFormated2.getHours()+' '+dateFormated2.getDate() + ' * *');
var j = schedule.scheduleJob(dateFormated2.getMinutes() +' '+dateFormated2.getHours()+' '+dateFormated2.getDate() + ' * *',function(){
var snm = new Date();
return stripe2.subscriptions.retrieve(req.user.subsID)
.then(subsData => {
console.log("Status = "+ subsData.status);
if(subsData.status == 'active')
{
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionDuplicateDate":req.user.subscriptionNextMonth }},
function (error, data) {
if (error) {
console.log(error);
return res.render("error",{error:error});
}
else if(req.user.subscriptionPlan == '$299' || req.user.subscriptionPlan == '$499' || req.user.subscriptionPlan == '$999')
{
snm = snm.setMonth(snm.getMonth() + 1);
console.log("snm = "+ snm);
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionNextMonth" : new Date(snm.toLocaleString())}},
function (error, data) {
if (error) {
console.log(error);
return res.render("error",{error:error});
}
})
console.log('Your scheduled job every month');
}
else if(req.user.subscriptionPlan == '$2990' || req.user.subscriptionPlan == '$4990' || req.user.subscriptionPlan == '$9990')
{
snm = snm.setFullYear(snm.getFullYear() + 1);
console.log("snm = "+ snm);
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionNextMonth" : new Date(snm.toLocaleString())}},
function (error, data) {
if (error) {
console.log(error);
return res.render("error",{error:error});
}
})
console.log('Your scheduled job every year');
}
})
}
else {
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionTotalCount" : 0}},
function (error, data) {
if (error) {
console.log(error);
return res.render("error",{error:error});
}
})
}
}).catch(err => {
res.render('error', {message: err});
});
});
if(req.user.subscriptionPlan == '$299' || req.user.subscriptionPlan == '$499' || req.user.subscriptionPlan == '$999')
{
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionDate":dateFormated,
"subscriptionDuplicateDate":dateFormated,
"subscriptionNextMonth":new Date(dateFormated.setMonth(dateFormated.getMonth() + 1))}},
function (error, data) {
if(data)
console.log("subscription date set");
})
}
else if(req.user.subscriptionPlan == '$2990' || req.user.subscriptionPlan == '$4990' || req.user.subscriptionPlan == '$9990')
{
User.findOneAndUpdate({_id:req.user.id},
{$set: {"subscriptionDate":dateFormated,
"subscriptionDuplicateDate":dateFormated,
"subscriptionNextMonth":new Date(dateFormated.setFullYear(dateFormated.getFullYear() + 1))}},
function (error, data) {
if(data)
console.log("subscription date set");
})
}
// console.log("subscription.items = "+ JSON.stringify(subscription.items));
console.dir(subscription);
res.redirect('/thankyou/0d4a3bc9cd71c4500584f01e7ce74cc6f2a4967ca266f3b7578ff29bd640dbbc/'+customer.id+'/'+subscription.id);
})
}).catch(err => {
res.render('error', {message: err});
});
});

Query is executed later then the return execution expressjs

I have a function that returns a certain json after it executes the query. but that json is coming as default, which i set, but i want the updated values from db.
Code :-
function addPet(pet) {
var body = {
msg : "",
insertId : null
};
console.log(pet.pet_type);
if(pet.pet_type){
mysql.mySqlConnection.query("insert into master_pet(pet_type) values(?)",[pet.pet_type], (err,rows,fields) => {
if(err){
console.log("Query Error :- " + err );
body.msg = "Error While Inserting";
body.insertId = null;
console.log("reached here");
return body;
}
else{
console.log("Inserted" + pet.pet_type);
console.log(rows.insertId);
body.msg = "Inserted Successfully";
body.insertId = rows.insertId;
console.log("reached here");
return body;
}
});
return body;
}
}
Calling Method :-
routes.post('/setPet',(req,res) => {
var pet = req.body;
var body = petmodel.addPet(pet);
res.setHeader('Content-Type', 'application/json');
res.json(body);
});
in here on the client, the json which I am receiving is default one.
Please help.
TIA
function addPet(pet, callback) {
var body = {
msg : "",
insertId : null
};
console.log(pet.pet_type);
if(pet.pet_type){
mysql.mySqlConnection.query("insert into master_pet(pet_type) values(?)",[pet.pet_type], (err,rows,fields) => {
if(err){
console.log("Query Error :- " + err );
body.msg = "Error While Inserting";
body.insertId = null;
console.log("reached here");
}
else{
console.log("Inserted" + pet.pet_type);
console.log(rows.insertId);
body.msg = "Inserted Successfully";
body.insertId = rows.insertId;
console.log("reached here");
}
return callback(body);
});
}
}
--
routes.post('/setPet',(req,res) => {
var pet = req.body;
petmodel.addPet(pet, (body) => {
res.setHeader('Content-Type', 'application/json');
return res.json(body);
});
});

access values after authentication in node js

I've a program that does the below.
Look into a DynamoDB table.
Get the data from the table.
Save the variables in session
After the process, print the values in console.
My code is as below.
intentHandlers['GetMYBusinessInfo'] = function (request, session, response, slots) {
console.log('entered ext bloxk');
if (!session.attributes.userName) {
console.log('eneterd the user entered the block');
var userName = 'jim';
isUserRegistered(userName.toLowerCase(), function (res, err) {
if (err) {
response.fail(err);
console.log(err);
}
else if (!res) {
response.shouldEndSession = true;
}
else {
console.log(res);
var countRes = JSON.stringify(res.Count);
var unpUserRegion = JSON.stringify(res.Items[0].Region);
var unpUserCity = JSON.stringify(res.Items[0].State);
var userRegion = JSON.parse(unpUserRegion);
var userCity = JSON.parse(unpUserCity);
session.attributes.city = userCity;
session.attributes.region = userRegion;
console.log("parsed " + countRes + "\t region is " + userRegion);
session.attributes.userName = true;
}
});
}
console.log(`session values after authentication are user city is ${session.attributes.city}`);
}
The method to check if the value is in DynamoDb or not.
function isUserRegistered(userName, callback) {
var params = {
TableName: "usersTable",
FilterExpression: "#nme = :nme",
ExpressionAttributeNames: {
"#nme": "Name",
},
ExpressionAttributeValues: {
":nme": userName
}
};
var count = 0;
docClient.scan(params, function (err, data) {
if (err) {
console.error("Unable to scan the table. Error JSON:", JSON.stringify(err, null, 2));
callback(false, err);
} else {
console.log("Scan succeeded." + data.Items.length);
if (data.Items.length === 0) {
callback(false);
}
else {
data.Items.forEach(function (itemData) {
console.log("Item :", ++count, JSON.stringify(itemData));
});
callback(data);
}
}
});
}
when I run this, the output that I get is:
session values after authentication are user city is undefined
Scan succeeded.1
Item : 1
{
"ID": "3",
"State": "wisconsin",
"Region": "midwest",
"Name": "jim"
}
{ Items: [ { ID: '3', State: 'wisconsin', Region: 'midwest', Name: 'jim' } ],
Count: 1,
ScannedCount: 1 }
parsed 1 region is midwest
Here I know that Node js being Non-blockable process, the above output is correct, but I want to get the value of city printed in session values after authentication are user city is {HereTheCityComes} instead of session values after authentication are user city is undefined.
I'm sure that placing the console.log(session values after authentication are user city is ${session.attributes.city}); in the last else block(place where the data is returned).
But I need this type of functionality(Get data as shown in my current scenario), as there is some other things to be done after checking if the user is available in database.
please let me know where am I going wrong and how can I fix this.
You can't synchronously expect async result.
What you can do here is solve your problem with promises.
Here is a solution:
intentHandlers['GetMYBusinessInfo'] = function(request, session, response, slots) {
console.log('entered ext bloxk');
var userPromise = Promise.resolve();
if (!session.attributes.userName) {
console.log('eneterd the user entered the block');
var userName = 'jim';
userPromise = new Promise(function (resolve, reject) {
isUserRegistered(userName.toLowerCase(), function (res, err) {
if (err) {
response.fail(err);
reject(err);
}
var countRes = JSON.stringify(res.Count);
var unpUserRegion = JSON.stringify(res.Items[0].Region);
var unpUserCity = JSON.stringify(res.Items[0].State);
var userRegion = JSON.parse(unpUserRegion);
var userCity = JSON.parse(unpUserCity);
session.attributes.city = userCity;
session.attributes.region = userRegion;
console.log("parsed " + countRes + "\t region is " + userRegion);
resolve(res);
});
});
}
userPromise.then(function () {
console.log(`session values after authentication are user city is ${session.attributes.city}`);
});
}
If you are not using ES6, then just install bluebird and use var Promise = require('bluebird')

node js mongo db dependencies (doc not being found)

I have the following code:
var method = PushLoop.prototype;
var agent = require('./_header')
var request = require('request');
var User = require('../models/user_model.js');
var Message = require('../models/message_model.js');
var async = require('async')
function PushLoop() {};
method.startPushLoop = function() {
getUserList()
function getUserList() {
User.find({}, function(err, users) {
if (err) throw err;
if (users.length > 0) {
getUserMessages(users)
} else {
setTimeout(getUserList, 3000)
}
});
}
function getUserMessages(users) {
// console.log("getUserMessages")
async.eachSeries(users, function (user, callback) {
var params = {
email: user.email,
pwd: user.password,
token: user.device_token
}
messageRequest(params)
callback();
}, function (err) {
if (err) {
console.log(err)
setTimeout(getUserList, 3000)
}
});
}
function messageRequest(params) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ params.email +"&api_password="+ params.pwd +"&method=getSMS&type=1&limit=5"
request(url, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
if (responseObject["status"] == "success") {
async.eachSeries(messages, function(message, callback){
console.log(params.token)
saveMessage(message, params.token)
callback();
}, function(err) {
if (err) {
console.log(err)
}
// setTimeout(getUserList, 3000)
})
} else {
// setTimeout(getUserList, 3000)
}
} else {
console.log(err)
// setTimeout(getUserList, 3000)
}
});
setTimeout(getUserList, 3000)
}
function saveMessage(message, token) {
// { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } }
// Message.find({ $and: [{ message_id: message.id}, {device_token: token}]}, function (err, doc){
Message.findOne({message_id: message.id}, function (err, doc){
if (!doc) {
console.log('emtpy today')
var m = new Message({
message_id: message.id,
did: message.did,
contact: message.contact,
message: message.message,
date: message.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: token
});
m.save(function(e) {
if (e) {
console.log(e)
} else {
agent.createMessage()
.device(token)
.alert(message.message)
.set('contact', message.contact)
.set('did', message.did)
.set('id', message.id)
.set('date', message.date)
.set('message', message.message)
.send();
}
});
}
}) //.limit(1);
}
};
module.exports = PushLoop;
Which actually works perfectly fine in my development environment - However in production (i'm using Openshift) the mongo documents get saved in an endless loop so it looks like the (if (!doc)) condition always return true therefore the document gets created each time. Not sure if this could be a mongoose issue - I also tried the "find" method instead of "findOne". My dev env has node 0.12.7 and Openshift has 0.10.x - this could be the issue, and i'm still investigating - but if anybody can spot an error I cannot see in my logic/code please let me know
thanks!
I solved this issue by using a "series" like pattern and using the shift method on the users array. The mongoose upsert findOneOrCreate is good however if there is a found document, the document is returned, if one isn't found and therefore created, it's also returned. Therefore I could not distinguish between the newly insert doc vs. a found doc, so used the same findOne function which returns null if no doc is found I just create it and send the push notification. Still abit ugly, and I know I could have used promises or the async lib, might refactor in the future. This works for now
function PushLoop() {};
var results = [];
method.go = function() {
var userArr = [];
startLoop()
function startLoop() {
User.find({},function(err, users) {
if (err) throw err;
users.forEach(function(u) {
userArr.push(u)
})
function async(arg, callback) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ arg.email +"&api_password="+ arg.password +"&method=getSMS&type=1&limit=5"
request.get(url, {timeout: 30000}, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
var status = responseObject.status
if (status === "success") {
messages.forEach(function(m) {
var message = new Message({
message_id: m.id,
did: m.did,
contact: m.contact,
message: m.message,
date: m.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: arg.device_token
});
var query = { $and : [{message_id: m.id}, {device_token: arg.device_token}] }
var query1 = { message_id: m.id }
Message.findOne(query).lean().exec(function (err, doc){
if (!doc || doc == null) {
message.save(function(e) {
console.log("message saved")
if (e) {
console.log("there is an error")
console.log(e)
} else {
console.log(message.device_token)
var messageStringCleaned = message.message.toString().replace(/\\/g,"");
var payload = {
"contact" : message.contact,
"did" : message.did,
"id" : message.message_id,
"date" : message.date,
"message" : messageStringCleaned
}
var note = new apns.Notification();
var myDevice = new apns.Device(message.device_token);
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.alert = messageStringCleaned;
note.payload = payload;
apnsConnection.pushNotification(note, myDevice);
}
})
}
});
});
}
else {
console.log(err)
}
}
});
setTimeout(function() {
callback(arg + "testing 12");
}, 1000);
}
// Final task (same in all the examples)
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(userArr.shift());
});
} else {
return final();
}
}
function final() {
console.log('Done');
startLoop();
}
series(userArr.shift())
});
}
}
module.exports = PushLoop;

Check if some query is undefined and define a callback in that case

I'm trying to do something like this:
var query = 'select max(count) from ' + series +
' where value = \'' + search + '\'';
if (db.query(query, callback) !== undefined) {
return callback;
} else {
return callback = [{
name: series,
columns: ['time', 'max'],
points: [
[0, 0]
]
}];
}
I'm trying to verify if that query is undefined or the element searched doesn't exist in the influxdb, and then arm a callback just like if the element exist, the if sentence works, but the else return an empty array
The db parameter is where are the data base configurations.
EDIT:
Thanks Osukaa for your answe. I try what you sugest but don't have response. Here is the complete function with your changes:
var counter = function (config, callback) {
var count = 'select max(count) from ' + series + ' where value = \'' + search + '\'';
db.query(count, function (err, res) {
if(err) return err;
if(res.length == 0){
return [{
name: series,
columns: ['time', 'max'],
points: [
[0, 0]
]
}];
}else{
return res;
}
});
};
The console.log shows an empty array.
EDIT 2:
Thanks #Osukaa, unfortunately that don't work, this is the error that returns:
Debug: handler, error
{"msec":395.7593630000483,"error":"Couldn't find series: items.type.updated"}
Debug: internal, error
Error: Couldn't find series: items.type.updated
EDIT 3:
I've solved the problem when try to create a series. When the series don't exist, show this error 'Error Couldn't find series [series name]', so I put this code in the error code:
db.query(qCount, function(err, res) {
if (err) {
if (err == 'Error: Couldn\'t find series: ' + name.series) {
res = newSeries;
return callback(null, res);
} else {
return callback(err);
}
} else {
if (res.length !== 0) {
return callback(null, res);
} else {
res = newSeries;
return callback(null, res);
}
}
});
When the error is equal to 'Error: Couldn\'t find series: ' + name.series, I pass the values to create them.
Thanks.
Asynchronous code doesn't work like that. When the db.query is completed it will automatically execute the callback code. It isn't necessary for you to do a return callback. Instead you could try something like this:
db.query('select max(count) from ' + series +
' where value = \'' + search + '\'' + ';', function (err, res) {
if(err) return err;
if(res.length == 0){
return [{
name: series,
columns: ['time', 'max'],
points: [
[0, 0]
]
}];
}else{
return res;
}
});
EDIT
First you make the GET to obtain the count
request.get('/itemCount')
.query({value: value.type})
.end(function(err, res) {
if (err) {
reply(err);
} else {
countElemnts(res.body[0].count);
}
});
So the server goes to the route and executes the handler:
server.route({
method: 'GET',
path: '/itemCount',
handler: function(request, reply) {
events.selectCount({
series: 'value.type',
search: request.url.query.value
}, function onSuccess(err, data) {
if (err) {
reply(err);
} else {
var result = {};
if (data.length !== 0) {
result = data[0].points.map(function(element) {
return {
count: element[1] + 1
};
});
reply(null, result);
} else {
reply(null, data);
}
}
});
}
});
Which itself calls the selectCount function to obtain the number (I updated the callback to return (null,res))
var selectCount = function(config, callback) {
var qCount = 'select max(count) from ' + config.series +
' where itemType = \'' + config.search + '\'';
db.query(qCount, function(err, res) {
if (err) {
return callback(err);
}else{
if (res !== undefined) {
return callback(null,res[0]);
}else{
var res = [{
name: config.series,
columns: ['time', 'count'],
points: [
[0, 0]
]
}];
return callback(null,res);
}
}
});
};
And when the callbacks finish, it should execute countElements:
var countElemnts = function(count) {
superagent
.post(config.eventsApiUrl)
.type('json')
.send({
name: 'items.type.updated',
data: {
id: request.params.id,
itemType: item.itemType,
count: count
}
})
.end(function() {
reply({
message: 'Item actualizado'
});
});
};

Resources