How can get two collection documents and calculate points using express.js? - node.js

exports.show = = function(req, res) {
var userdata = [{
"productcode": "9563456789",
"cost": "1000"
}, {
"productcode": "8756348947",
"cost": "5600"
}]
var parameterObject = [];
Parameter.find().exec(function(err, Parameters) {
if (err) {
return handleError(res, err);
}
// i want to push Parameters[0].value to parameterObject
parameterObject.push({
pointvalue: Parameters[0].value
});
});
for (var i = 0; i < userdata.length; i++) {
Product.find({
'productcode': userdata[i].productcode
}).exec(function(err, Products) {
if (err) {
return handleError(res, err);
}
var point = 0;
if (!Products) {
point = 0;
} else if (Products[0].product.point > 0) {
point = Products[0].product.point;
}
if (point > 0) {
// here i am not getting userdata[i].cost
//parameterObject.pointvalue value also not getting
totalprice = userdata[i].cost / parameterObject.pointvalue * point;
}
});
}
};
Here i have written function for calculating totalprice. i have mentioned userdata(this is my req.body).
Expectation :
i need to store Parameters objects in some variable to access where ever i want.
i want to pass userdata object in Product.find() function
how can i calculate this
totalprice= userdata[i].cost/parameterObject.pointvalue) * point);

exports.show = = function(req, res) {
var userdata = [{
"productcode": "9563456789",
"cost": "1000"
}, {
"productcode": "8756348947",
"cost": "5600"
}]
var parameterObject = [];
Parameter.find().exec(function(err, Parameters) {
if (err) {
return handleError(res, err);
}
// i want to push Parameters[0].value to parameterObject
parameterObject.push({
pointvalue: Parameters[0].value
});
return FindProducts(parameterObject, function(data) {
console.log(data);
});
});
function FindProducts(parameterObject, callback) {
for (var i = 0; i < userdata.length; i++) {
var totalprice = 0;
findProduct(i, parameterObject, function(i, price) {
totalprice += price;
if (i <= userdata.length) {
return callback({
"userid": "myuserid",
"total": totalprice
});
}
});
}
}
function findProduct(i, parameterObject, callback) {
Product.find({
'productcode': userdata[i].productcode
}).exec(function(err, Products) {
if (err) {
return handleError(res, err);
}
var point = 0;
if (!Products) {
point = 0;
} else if (Products[0].product.point > 0) {
point = Products[0].product.point;
}
if (point > 0) {
// here you can now get the value of userdata[i].cost
// here you can now get the value of parameterObject
totalprice = userdata[i].cost / parameterObject[0].pointvalue * point;
return callback(i, totalprice);
}
});
}
};

You can use promises when you want to use the result of two functions and later use it for further computation.
In your case, you can execute the two asynchronous functions in parallel. It can look like this.
Promise.all([
asyncFunc1(),
asyncFunc2(),
])
.then(function(result){
// result is an array and has the response of the functions which is
// result[0] and result[1]
···
// you can manipulate the result of the functions here
})
.catch(function(err){
// Receives rejection/error among the Promises
···
});
Here asyncFunc1() will be your first find function
asyncFunc2() will be your second find function.
The result[0] and result[1] will be the results of the functions respectively.
Later you can use the result to do further computations.
Hope this helps.

Related

How to return 2 arrays after saving data to mongodb using node js

I need help with code below. I get an array of items from the client then the goal is to save them in mongodb and return the list classified as 'saved' and 'failed' items. sample of failed items are those that are duplicate on a unique attribute.
I know the code below will not work because of variable scope. how do i get around it? the code below returns an empty array for both savedItems and failedItems. Thanks!
router.post('/addItems', async (req, res, next) => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
function saveData() {
for (i = 0; i < items.length; i++) {
item = items[i];
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
});
}
return result;
}
saveData().then(result => {
res.send({
results: result
});
});
});
router.post('/addItems', async (req, res, next) => {
// use try catch when use async
try {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
for (let i = 0; i < items.length; i++) {
const item = items[i];
// use the returned promise instead of callback for Model.create
const data = await Model.create({ ...item });
result.savedItems.push(item);
// if also need to handle failed item in result use anathor try catch inside
/*try {
const data = await Model.create({ ...item });
result.savedItems.push(item);
} catch( err ) {
result.failedItems.push(item);
}*/
}
res.send({
results: result
});
} catch( err ) {
// To all the errors unexpected errors + thrown rejected promises
res.send({
error: err
});
}
});
Your saveData method didn't return a promise, try this
function saveData() {
return new Promise(resolve => {
let items = req.body;
let result = {
savedItems: [],
failedItems: []
};
let promises = [];
for (i = 0; i < items.length; i++) {
item = items[i];
let promise = new Promise(resolve => {
Model.create({ ...item }, (err, data) => {
if (err) {
result.failedItems.push(item);
} else {
result.savedItems.push(item);
}
resolve();
});
});
promises.push(promise);
}
Promise.all(promises).then(() => resolve(result));
})
}

NodeJS Callback not returning completed array outside for loop

I've got an empty object array "storing" and I'm currently pushing objects in a nested for loop. This issue is when I call the callback(null, storing) outside the for loop it returns an empty array. Should I be running a promise call? Not sure where to go from here
var params = {
TableName: USER_TABLE,
KeyConditions: {
orgid: {
ComparisonOperator: 'EQ',
AttributeValueList: [org_uuid]
},
orgkey: {
ComparisonOperator: 'EQ',
AttributeValueList: [secret_key]
}
}
};
// query table for devices tied to user
dynamodb.query(params, function(err, data) {
if (err) {
badRequest();
} else {
// check whether correct org_uuid & org_key has been passed
var checked_org = data.Items[0].org_key;
if (checked_org == secret_key) {
var storing = [];
var value = data.Items[0].read.values;
for (var x = 0; x < value.length; x++) {
var query_params = {
TableName: DEVICE_TABLE,
KeyConditions: {
device_id: {
AttributeValueList: {
S: value[x]
},
ComparisonOperator: 'EQ'
}
}
};
dynamodb.query(query_params, function(err, data) {
if (err) {
console.log(err);
} else {
for (var i = 0; i < data.Count; i++) {
storing.push(data.Items[i].device_id);
}
}
});
}
callback(null, storing)
}
}
});
}

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);
}
});
}

nodejs issue with undefined promise nodejs using Q

I've been wrappingmind over async and sync functions as a php developer ive never had to worry about this much. so my issue is this
i have a function
function loadPartnerInventory(args,itemIds,offers,offer) {
var deferred = Q.defer();
offers.loadPartnerInventory(args, function(err, items) {
var checkItems = [];
var len = items.length;
for(var i = 0; i < itemIds.length; i++) {
for(var j = 0; j < items.length; j++) {
if (itemIds[i] == items[j].id){
//console.log('Pushed: ' + items[j].name);
checkItems.push({
itemname: items[j].market_name,
market_hash_name: items[j].market_hash_name,
steamid: offer.steamid_other,
tradeofferid : offer.tradeofferid
});
}
}
}
deferred.resolve(checkItems);
});
return deferred.promise;
}
function loadMyInventory(args,itemIds_g,offers,offer) {
var deferred = Q.defer();
offers.loadMyInventory(args, function(err, itemsg) {
var checkItems_g = [];
var len = itemsg.length;
for(var i = 0; i < itemIds_g.length; i++) {
for(var j = 0; j < itemsg.length; j++) {
if (itemIds_g[i] == itemsg[j].id){
console.log('Pushed: ' + itemsg[j].name);
checkItems_g.push({
itemname: itemsg[j].market_name,
market_hash_name: itemsg[j].market_hash_name,
steamid: offer.steamid_other,
tradeofferid : offer.tradeofferid
});
}
}
}
deferred.resolve(checkItems_g);
});
return deferred.promise;
}
function getPartnerInventory(offers, offer, itemIds, itemIds_g) {
var p1 = loadPartnerInventory({
partnerSteamId: offer.steamid_other,
appId: 730,
contextId: 2
},itemIds,offers,offer);
var p2 = loadMyInventory({appId: 730, contextId: 2},itemIds_g,offers,offer);
return Q.all(p1, p2).spread(function(checkItems, checkItems_g) {
return {
checkItems: checkItems,
checkItems2: checkItems_g
};
});
}
im doing this to get results, but somehow the second prommiss is undefined and i dont understand why.
getPartnerInventory(offers,offer,itemIds,itemIds_G).then(function(response) {
console.log(response);
//console.log(response);
});
checkitems returns correctly yet checkitems 2 is undefined.
cosole log is :
{ checkItems:
{ itemname: 'Operation Breakout Weapon Case',
market_hash_name: 'Operation Breakout Weapon Case',
steamid: '76561198245431424',
tradeofferid: '859881697' },
checkItems2: undefined }
Pushed: Glock-18 | Wraiths
as can see it its undiefined but seems to add item after its done
You cannot resolve the same promise twice. You should wrap both methods in separate promises and then use Q.all(), which will return a new promise to be resolved only after both promises have been successfully resolved. For example:
function mapOfferItem(item, offer) {
return {
itemname: item.market_name,
market_hash_name: item.market_hash_name,
steamid: args.offer.steamid_other,
tradeofferid : args.offer.tradeofferid
};
}
function loadPartnerInventory(args) {
var deferred = Q.defer();
offers.loadPartnerInventory(args, function(err, items) {
var checkedItems = items.filter(function(item) => {
return args.itemIds.indexOf(item.id) >= 0;
}).map(function(item) {
return mapOfferItem(item, args.offer);
});
deferred.resolve(checkedItems);
});
return deferred.promise;
}
function loadMyInventory(args) {
var deferred = Q.defer();
offers.loadMyInventory(args, function(err, items) {
var checkItems = items.filter(function(item) {
return args.itemIds_g.indexOf(item.id);
}).map(function(item) {
return mapOfferItem(item, args.offer);
});
deferred.resolve(checkItems);
});
return deferred.promise;
}
function getPartnerInventory(offers, offer, itemIds, itemIds_g) {
var p1 = loadPartnerInventory({
partnerSteamId: offer.steamid_other,
appId: 730,
contextId: 2
});
var p2 = loadMyInventory({appId: 730, contextId: 2});
return Q.all([p1, p2]).spread(function(checkItems, checkItems_g) {
return {
checkItems: checkItems,
checkItems2: checkItems_g
};
});
}
You can then use the function like this:
getParentInventory(offers, offer, itemIds, itemIds_g)
.then(function(checkItems) {
console.log(checkItems);
// should print {checkItems: [...], checkItems2: [...]}
});

How to make this code execute in an appropriate order

I'm writting a web application in node.js which uses mongodb. I have this piece of code but unfortunatelly it does not execute in order, I mean for loops iterate faster than those db functions are executed and this makes little mess.
hospitalsCollection.update({}, {$pull: {doctors: parseInt(id)}}, function(err, success) {
treatmentsCollection.update({}, {$pull: {doctors: parseInt(id)}}, function(err, success) {
hospitalsCollection.find({"_id": {$in: hospitalsIds}}).toArray(function(err, hospitalsList) {
for(i = 0; i < hospitalsList.length; i++) {
for(j = 0; j < hospitalsList[i].treatments.length; j++) {
var exists = false;
for(k = 0; k < hospitalsList[i].doctors.length; k++) {
doctorsCollection.find({"_id": parseInt(hospitalsList[i].doctors[k])}).toArray(function(err, doctorObj) {
for(l = 0 ; l < doctorObj.treatments.length; l++) {
if(doctorObj.treatments[l] == hospitalsList[i].treatments[j]) {
exists = true;
break;
}
}
});
if(exists)
break;
}
if(exists) {
break;
}
else {
hospitalsCollection.update({"_id": parseInt(hospitalsList[i]._id)}, {$pull: {treatments: parseInt(hospitalsList[i].treatments[j])}}, function(err, success) {
treatmentsCollection.update({"_id": parseInt(hospitalsList[i].teratments[j])}, {$pull: {hospitals: parseInt(hospitalsList[i]._id)}}, function(err, success) {
console.log(err);
});
});
}
}
}
for(i = 0; i < treatments.length; i++) {
doctorsCollection.aggregate([ {$project:{"treatments._id":1, "treatments.price":1}}, {$unwind:"$treatments"},{$match:{"treatments._id": parseInt(treatments[i])}}, {$sort:{"treatments.price":-1}}, {$limit:1} ], function(err, result) {
doctorsCollection.aggregate([ {$project:{"treatments._id":1, "treatments.price":1}}, {$unwind:"$treatments"},{$match:{"treatments._id": parseInt(treatments[i])}}, {$sort:{"treatments.price":1}}, {$limit:1} ], function(err, result2) {
var maxPrice = result[0].treatments.price;
var minPrice = result2[0].treatments.price;
treatmentsCollection.update({"_id": parseInt(treatments[i])}, {$set: {"maxPrice": parseInt(maxPrice)}}, function(err, success) {
treatmentsCollection.update({"_id": parseInt(treatments[i])}, {$set: {"minPrice": parseInt(minPrice)}}, function(err, success) {
console.log(err);
});
});
});
});
}
});
});
});
I really don't know how to handle this. Any help would be appreciated.Thanks.
Use Promise (bluebird is great). And refactor your code.
With Promise, you can do something like below.
dbUpdate1()
.then(function(resultFromUpdate1) {
let multipleUpdates = []
multipleUpdates.push(updateCollectionA())
multipleUpdates.push(updateCollectionB())
return Promise.all(multipleUpdates)
.spread(afterUpdatingBothCollection)
function updateCollectionA(argument) {
// body...
}
function updateCollectionB(argument) {
// body...
}
function afterUpdatingBothCollection(resultFrom1, resultFrom2) {
// body...
}

Resources