Update and get lastest data in one function - node.js

I have the following javaScript code for Nodejs to update data in MongoDB.
I have a list of products that I want update (called itemsToBeUpdated). (Update the preference value in the order that they are passed-in)
Once all the updates have been completed, I would like to go and retrieve the product list by calling the function getProducts(req, res);
where should I put the getProducts(req, res)? Not position A because Product.findByIdAndUpdate is async so it will get to position A before the findByIdAndUpdate is completed.
Not position B because there are more items to loop through.
const updateAndRefreshProducts = (req,res) => {
const itemsToBeUpdated = req.body;
const counter = someValue
for(let i = 0; i<itemsToBeUpdated.length; i++){
const newPreference = counter;
counter++;
condition= {_id: itemsToBeUpdated[i]._id};
Product.findByIdAndUpdate(condition, {preference:newPreference})
.then(result => {
console.log('performing update completed for result' + result.name +" : ", result.preference);
//position B
})
.catch(error =>{
console.log('error', error);
});
}
//position A
}
thanks

There are a couple of way to handle this, the easiest way to accomplish this will be to utilize Promise.all().
You may want to read on this documentation
const updateAndRefreshProducts = (req,res) => {
const itemsToBeUpdated = req.body;
const productUpdatePromises = []
const counter = someValue
for(let i = 0; i<itemsToBeUpdated.length; i++){
const newPreference = counter;
counter++;
condition= {_id: itemsToBeUpdated[i]._id};
const productUpdatePromise = Product.findByIdAndUpdate(condition{preference:newPreference})
productUpdatePromises.push(productUpdatePromise)
}
await Promise.all(productUpdatePromises).then((results) => {
console.log(results);
//Called your get all products here
})
.catch((error) => {
console.error(error.message);
});
}

Related

Trouble updating an outer array from inside a mongoose query

I have an array that I'd like to fill with objects, but the console prints out []. I know this is a problem with the async nature of mongoose, but I'm not sure how to fix it... I want itemCart to be filled with all the user's items.
Any guidance/help would be appreciated. Thanks!
Here is the code:
let itemCart = [];
User
.findById(req.params.username)
.then(user => {
for (let i = 0; i < user.cart.length; i++) {
let itemId = user.cart[i];
Item.findById(itemId).then(item => {
itemCart.push(item);
});
}
console.log(itemCart); // returns []
})
.catch(err => {
console.error(err)
});
You can apply async/await like this:-
let itemCart = [];
User
.findById(req.params.username)
.then(async user => {
for (let i = 0; i < user.cart.length; i++) {
let itemId = user.cart[i];
Let item = await Item.findById(itemId);
itemCart.push(item);
}
console.log(itemCart); // now it will return the array
})
.catch(err => {
console.error(err)
});

Formatting MongoDb response for API

I'm trying to retrieve a collection in MongoDb and the problem is the API already responds even though the processing is not yet done. So basically what I'm trying to do is retrieve the results using find, iterate through the results using foreach, and push each row to an array.
I've tried a variety of suggestions but none work so far. Below is a rough idea of what I'm trying to pull off.
get: async function (req, res, next) {
let messagesArray = []
let sessionId = req.query.session
client.connect(err => {
try{
const collection = client.db("xxxxxxx").collection("xxxxxxx")
let results = collection.find({},{sessionId:sessionId})
for (const result of results){
order = {"text" : order.partner+", "+order.order+ ", "+order.quantity}
messagesArray.push(order)
}
}
catch(e){
}
client.close()
res.send(200,{messages:messagesArray})
})
},
for loop will execute asynchronous so before your for loop is getting finished res is sent so try for the following
get: async function (req, res, next) {
let messagesArray = []
var counter = 0;
let sessionId = req.query.session
client.connect(err => {
try{
const collection = client.db("xxxxxxx").collection("xxxxxxx")
let results = collection.find({},{sessionId:sessionId})
for (const result of results){
order = {"text" : order.partner+", "+order.order+ ", "+order.quantity}
messagesArray.push(order)
counter++;
if(counter == results.length) {
client.close()
res.send(200,{messages:messagesArray})
}
}
}
catch(e){
}
})
},
use await to wait for result to available :
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
get: async function (req, res, next) {
let messagesArray = []
let sessionId = req.query.session
const client = await MongoClient.connect(url, { useNewUrlParser: true }).catch(err => { console.log(err); });
if (!client) { return;}
try{
const collection = client.db("xxxxxxx").collection("xxxxxxx")
let results = await collection.find({sessionId:sessionId})
console.log(results);
// ...
}
catch(e){
console.log(e);
}
finally {
client.close();
}
},

How to save each array to each document with 'for' in Nodejs with mongoose

I want to save each array data into each document at Nodejs.
Therefore I made this code below.
But when I run this code, it only saves body[0].
Could you recommend some solution?
exports.saveOrder = (req, res) => {
const body = JSON.parse(res);
for (let i = 0; i < body.length; i += 1) {
const eachBody = body[i];
const order = new Order(eachBody);
order.save();
return res.send('order is saved');
}
}
}
};
For Db operations, You need to use promise or async/await, and send response once after all orders saved to DB. Add try/catch to catch errors as well.
Check this code, it should work now.
exports.saveOrder = async (req, res) => {
try {
const body = JSON.parse(res); // check this before do you realy need to parse it or not
const allResults = [];
for (let i = 0; i < body.length; i += 1) {
const eachBody = body[i];
const order = new Order(eachBody);
const result = await order.save();
allResults.push(result);
}
return res.send(allResults);
} catch (e) {
console.log(e);
return res.send(e);
}
};
This is because you have send the response(used return) inside the for loop.
So it saves body[0] and return the response.
Use "return" outside the "for loop".
for (let i = 0; i < body.length; i += 1) {
const eachBody = body[i];
const order = new Order(eachBody);
order.save();
}
return res.send('order is saved');

How to Loop Data and Validate in Mongodb

I have a dynamic input field where user can add multiple category at once. Data sent at backend is like
['ELECTRONIC','TOYS','GAMES']
Now I want to check for each element of the array ,if they are already present on mongodb . If its present i want to store it in errors object as
errors={ 0: 'Duplicate Data found'}
I am attaching my code for validation which is not working please help . .
const Category = require('../../models/Category');
const fieldCheck = (req, res, next) => {
const data = req.body;
const errors = [];
for( i = 0; i < data.length ; i++){
Category.findOne({ category_name : data[i]})
.then(user => {
if(user){
// # If a reqistered User ID is found ,then move ahead
errors[i] = 'Duplicate Entry Found';
errors.push(errors[i]);
}
}).catch(err =>{
return res.json(err);
}
)
}
console.log(errors);
};
module.exports = fieldCheck;
My Category Schema is ....
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const categorySchema = new Schema ({
category_name:{
type:String,
unique:true,
isRequired:true,
},
date:{
type:Date,
default:Date.now()
}
});
module.exports = mongoose.model('Category',categorySchema);
You are trying to call an asynchronous method (findOne) inside a synchronous loop (for). As you experience, this is like oil and water.
An easy fix is to make your method asynchronous and use the await keyword, example:
const fieldCheck = async (req, res, next) => {
const data = req.body;
const errors = [];
try {
for( i = 0; i < data.length ; i++) {
let user = await Category.findOne({ category_name : data[i]});
if (user) {
// # If a reqistered User ID is found ,then move ahead
errors[i] = 'Duplicate Entry Found';
errors.push(errors[i]);
}
}
// I assume you wanted to respond to res.json here?
console.log(errors);
} catch (err) {
return res.json(err);
}
};
module.exports = fieldCheck;

Getting empty array in nodejs

I am posting value But I am getting empty array . I know its node asynchronous problem . But I don't know how do i solve this. I have refer this following link:
How do I return the response from an asynchronous call?
But I could not able to understand . Kindly help me to understand promises and how do i use that in my code.
router.post('/inspection_list', function (req, res) {
var id = req.body.project_id;
console.log(id)
// res.send("ok")
db.inspection.findOne({'_id':id},(err,response)=>{
if(err){
console.log("error");
}
else{
console.log("Data")
var inspection = [];
var data = response.inspection_data;
var f = data.map(function (item) {
var fielduser = item.fielduser_id
db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)},(err,user)=>{
console.log(user.owner_name);
console.log(item.inspection_name)
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
})
});
console.log(inspection) // Here am getting empty value
// setTimeout(function(){ console.log(inspection) }, 5000); my timeout code
}
})
});
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; i++){
var item = data[i]
var fielduser = item.fielduser_id
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
}
catch(err){
throw err
}
})
This uses async and await, you can use it if you are using node version >=7.6
Also note the following:
router.post('/inspection_list', async function (req, res)
Handling each error seperately
router.post('/inspection_list', async function (req, res) {
var id = req.body.project_id;
try{
var response = await db.inspection.findOne({'_id':id})
}
catch(err){
// handle error here
throw err
}
var inspection = [];
var data = response.inspection_data;
for ( var i = 0; i<data.length; var item = data[i]
var fielduser = item.fielduser_id
try{
var user = await db.fielduser.findOne({'_id': mongoose.Types.ObjectId(fielduser)})
}
catch(err){
// handle error
}
inspection.push({inspection_name:item.inspection_name,field_user_name : user.owner_name})
}
})
Using mongoose would be the easy way out, it returns Promises for all query and save functions, so you'd simply do:
YourModel.findOne({params}).then(() => {...})
If you're unable to do that, in your case, a 'promisified' example would be:
var findAndFillArray = (project_id) => new Promise((resolve) => {
.... your previous code here ....
inspection.push({inspection_name:item.inspection_name,field_user_name :
user.owner_name})
if (data.length === inspection.length){ // Or some other preferred condition
resolve(inspection);
}
})
Then you'd call this function after you get the id, like any other function:
var id = req.body.project_id;
findAndFillArray(id).then((inspection_array) => {
res.send(inspection_array) // Or whatever
})
Now, map and all list functions are synchronous in JS, are you sure the error is due to that?

Resources