Javascript function returning undefined from mongodb function - javascript

Hi I get data from mongoDB and I try insert new data from other function. For some reason I get undefined.
What I'm doing is wrong and how can I fix it?
router.post("/list", (req, res, next) => {
const params = req.body;
var results_data = [];
Countability.find()
.populate("user")
.populate("company")
.populate("store")
.exec(function (err, data) {
_.forEach(data, function (value, key) {
results_data[key] = {
_id: value._id,
count: GetCount(10)
};
});
res.status(200).json({ status: 1, result: results_data });
});
});
const GetCount = (id) => {
DataRow.aggregate(
[
{
"$group": {
"_id": "$rowName",
"count": { "$sum": 1 }
}
}
]).exec((err,res) => {
var data = Promise.all([res]);
data.then(function (res) {
return res
})
})
}

Though the forEach has not finished,server starts sending response.
You need to make sure the results_data has got all data,then call res.status(200).json

Related

MongoDB $set to update subarray, adding new entry instead of updating

im trying to update an oject in a sub-array and instead of replacing and updating the data. it adds a new enetry.
controller.js:
const updateSubCategory = asyncHandler(async (req, res) => {
const {
dataArray
} = req.body
const categories = await Category.find({})
if (categories) {
await Category.updateOne({
"SubCats._id": req.params.id
}, {
"$set": {
SubCats: {
name: dataArray[0],
image: dataArray[1]
}
}
}, {
"multi": true
})
res.json({
message: 'sub-category updated'
})
} else {
res.status(404)
throw new Error('Error')
}
})
I think you need this, but i am not sure, if you dont need this, if you can give sample data and expected output in json.
You can try an example PlayMongo
It updates the fields inside not replace all the embeded document (your query does that).
const updateSubCategory = asyncHandler(async (req, res) => {
const {
dataArray
} = req.body
const categories = await Category.find({})
if (categories) {
await Category.updateOne({
"SubCats._id": req.params.id
}, {
"$set": {
"SubCats.name" : dataArray[0],
"SubCats.image" : dataArray[1]
}
}
}, {
"multi": true
})
res.json({
message: 'sub-category updated'
})
} else {
res.status(404)
throw new Error('Error')
}
})

How to push inside nested array of object that have a precise value of a key in MongoDB?

I have one question about a problem that I'm not able to fix. I try to update push a string passed via Query in my mongoose collection.
My collection are like this:
{
"_id": {
"$oid": "6199288597e42bf84d017f9e"
},
"name": "Lisa",
"surname": "Bianchi",
"ID_school": "afbH598U3",
"classes": [
{
"class": "5A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017f9f"
}
},
{
"class": "1A",
"activities": {
"in_progress": [],
"finisched": []
},
"_id": {
"$oid": "6199288597e42bf84d017fa0"
}
}
],
"email": "insegnante#a.com",
"__v": 0
}
and I try to push a string in in_progress array that match, for example, with class:"5A" using this way:
import db from "../models/index.js";
const Teacher = db.teacher
const updateActivity = (req, res) => {
const query = { _id: req.query.id};
const update = {$push:{'classes.$[group].activities.in_progress': req.query.data } };
const options = {arrayFilters: { 'group.class': req.query.class }};
Teacher.findOneAndUpdate(query, update, options).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
const API = {
updateActivity
}
export default API
The query works fine, but nothing was pushed. I tested whit Insomnia passing in the Query field
id = 6199288597e42bf84d017f9e;
class:'5A';
data:"pushed"
Any suggestion? Thanks!
try this way by passing classes.class in query and also change push to $push:{'classes.$.activities.in_progress': req.query.data }
const updateActivity = (req, res) => {
const query = { _id: req.query.id ,'classes.class': req.query.class};
const update = {$push:{'classes.$.activities.in_progress': req.query.data } };
Teacher.updateOne(query,update).exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
})
}
There are two ways of doing this:
Option 1: arrayFilters - more flexible Docu
The option you are using.
You have a syntax error - arrayFilters should be an array of documents.
const updateActivity = (req, res) => {
const query = { _id: req.query.id };
const update = {
$push:{ 'classes.$[group].activities.in_progress': req.query.data }
};
// This MUST be an array of filter documents!
const options = { arrayFilters: [{ 'group.class': req.query.class }] };
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}
Option 2: Via Query (as answered by #Saurabh Mistry)
Repeating his answer for completeness
By specifying a query that targets a particular element in an array within result documents.
const updateActivity = (req, res) => {
const query = {
_id: req.query.id,
'classes.class': req.query.data,
};
const update = {
$push:{ 'classes.$.activities.in_progress': req.query.data }
};
Teacher
.findOneAndUpdate(query, update, options)
.exec((err, data) => {
if (err) {
res.status(400).send({ message: err });
return;
} else {
res.status(200).send(data);
}
});
}

How adding a field from a pulled mongodb document

I am trying to use an api to get the current value of a stock and multiply by the users stock.
When I make a call the route I get empty data, and when I print the value of the callback I get an empty array
function user_cur_portfolio(port, callback) {
let portfolio = [];
port.forEach( (stock) => {
var ticker = stock.name.toLowerCase();
alpha.data.quote(`${ticker}`).then(data => {
var fixed = Number((data['Global Quote']['05. price'] * stock.shares).toFixed(2));
let curr = {
name : ticker,
shares: stock.shares,
value : fixed
}
portfolio.push(curr)
});
})
callback(portfolio)
}
router.get('/portfolio', (req, res, next) => {
if (req.session.userId !== undefined){
User.findOne({ _id : req.session.userId }).exec(function (err, user) {
if (err)
next(err);
user_cur_portfolio(user.portfolio, (port)=>{
console.log(port);
res.render('portfolio', { portfolio: port, balance: user.balance});
});
})
} else {
res.redirect('/users/login');
}
});
When I make a call the route I get empty data Because alpha.data.quote is an async function and forEach is a sync function therefore, you will not be getting data in port variable.
So the best work around to this, is to use async await with all the synchronous function to behave them like async
async function user_cur_portfolio(port) {
let portfolio = [];
await Promise.all(
port.map(async stock => {
var ticker = stock.name.toLowerCase();
const data = await alpha.data.quote(`${ticker}`);
var fixed = Number((data['Global Quote']['05. price'] * stock.shares).toFixed(2));
let curr = {
name: ticker,
shares: stock.shares,
value: fixed
};
portfolio.push(curr);
})
);
return portfolio;
}
router.get('/portfolio', (req, res, next) => {
if (req.session.userId !== undefined) {
User.findOne({ _id: req.session.userId }).exec(async function(err, user) {
if (err) next(err);
const port = await user_cur_portfolio(user.portfolio);
console.log(port);
res.render('portfolio', { portfolio: port, balance: user.balance });
});
} else {
res.redirect('/users/login');
}
});

returning null when using value out of block

I am trying to query one collection, get IDs from that and with that I am querying another collection and send the response. No issue in that. My issue is I am using foreach, so I am trying to get the value out of block and send the response. But it's throwing null. I consoled the value inside the block, its giving the response but I couldn't access the value out of the block.
Code
getDetails = async (req, res) => {
let data: any[] = [];
await employee.find({
_id: new mongoose.Types.ObjectId(req.body.id)
}, (err, obj) => {
if (err) {
console.log("No Such Employee")
} else {
obj.forEach(element => {
employer.find({
user: new mongoose.Types.ObjectId(element.user)
}, (err, details) => {
if (err) {
console.log("No such employer")
} else {
for (var i = 0; i < detail.length; i++) {
let p_info = {
"id": detail._id,
"fname": details[i].fname "lname": details[i].lname "phone": details[i].phone,
"email": details[i].email,
}
data.push(p_info); // I can get value here
}
}
})
});
res.send(data); // Cannot get value here
}
});
}
return response only when all your asynchronous db calls are done. see below:
getDetails = async(req, res) => {
let data = [];
let employees;
try {
employees = await employee.find({
_id: new mongoose.Types.ObjectId(req.body.id)
});
} catch (err) {
console.log("No Such Employee");
}
let emp_len = employees.length;
employees.forEach((emp_obj, idx) => {
let details = await employer.find({
user: new mongoose.Types.ObjectId(emp_obj.user)
});
for (var i = 0; i < patient.length; i++) {
let p_info = {
"id": patient._id,
"fname": details[i].fname,
"lname": details[i].lname,
"phone": details[i].phone,
"email": details[i].email,
}
data.push(p_info); // I can get value here
}
if (emp_len == idx + 1) {
res.send(data); // Cannot get value here
}
});
}

how can i print result array in node js outside mongoOp find query?

I am new in Node.js and I want to pass data array to controller. But I am unable to insert for loop data in array and I also want to get result data out side function.
router.get("/list-group", function(req, res) {
sess = req.session;
var response = {};
if (sess.loginData) {
var TableData = [];
var i = {};
var result = [];
mongoOp.users_group.find({
group_id: req.query.group_id
}, function(e, d) {
var len = d[0].assign_user_id.length;
var assignuserid = d[0].assign_user_id;
for (var i = 0; i < assignuserid.length; i++) {
var assignid = assignuserid[i];
mongoOp.users.find({
_id: assignid
}, function(err, data) {
// This is result array
result[i] = data;
})
}
// And I want to print result array here
console.log(result);
});
} else {
response = {
"error": true,
"message": "Invalid Login"
};
res.json(response);
}
})
I would make use of async and await
router.get('route', (req, res) => {
// ...
users.find(query, (err, d) => {
try {
// ...
var results = []
for (var data of array) {
const result = await fetchUser(data)
results.push(result)
}
console.log(results)
} catch (err) {
console.log('some error occured', err)
}
})
})
async function fetchUser(id) {
return new Promise((resolve, reject) => {
users.find({ _id: id }, (err, data) => {
return err ? reject(err) : resolve(data)
})
})
}
If you're not that familiar with async and await I would recommend this video
u need read about async and callbacks in javascript. An alternative is read about async and await.

Categories