Loop through array and add data - node.js

I have an array called "content". In this array is the "asin-id" (It's a kind of product ID). I'm trying to loop through the content array and get from the asin-id the specific product so I can add the product to the array and save the new content-array in the db.
Something is wrong. I don't know how to do it.
Expected result:
content: [{ asin: "asin-ID", product: product }, ...]
What I tried:
exports.createBlogPost = async (req, res) => {
try {
const content = req.body.content
content.map(async (element) => {
const asin = element.asin
const product = await Product.findOne({ asin: asin })
element.product = product
return element
})
console.log(content)
const post = new BlogPost({
postTitle: req.body.postTitle,
postQuery: req.body.postQuery,
content: content,
mainImage: req.file
})
console.log("Saved: " + post)
await post.save()
if(post) {
return res.status(200).json({
success: true,
message: 'Saved blog post successfully',
post: post
})
}
} catch(err) {
console.log(err)
}
}

I think the problem may be simply that you're using map without assigning the result to a variable. Try replacing your code with something similar to the following:
let updatedContent = content.map(async (element) => {
const asin = element.asin
const product = await Product.findOne({ asin: asin })
element.product = product
return element
})
console.log(updatedContent)

Related

Firebase nodejs doesn't execute return function properly

We are trying to get timeslots from our database by pushing them into an array and then returning it. The array does get filled properly according to the firebase logs, however the function never returns the data properly at all, even though we see the data to be returned.
Basically, the execution does not reach the return statement.
Our goal is to get all of the timeslots in this photo. Is there any neat way to do this?
exports.getTimeslots = functions.region('europe-west2').https.onCall((data, context) => {
const uid = context.auth.uid;
let array = [];
if (!uid)
throw new functions.https.HttpsError('no-userid', 'The requested user was not found');
else
return admin.firestore().collection('users').doc(uid).collection('modules').where('name', '!=', '').get().then(snapshot => {
snapshot.forEach(async doc => {
await admin.firestore().collection('users').doc(uid).collection('modules').doc(doc.id).collection('timeslots').where('length', '!=', -1).get().then(snapshot2 => {
snapshot2.forEach(doc2 => {
array.push(Object.assign(doc2.data(), {id: doc2.id, modID: doc.id}))
console.log("identifier #1", array)
})
console.log("Got outside");
})
console.log("Got more outside");
})
console.log("Got the most outside")
return ({ data: array });
});
//console.log("I have escaped!")
})
As #Ragesh Ramesh also said: "The solution is to make everything async await.", I tried replicating your code using the data structure, and code below:
Data Structure:
Code:
// firebase db
const db = firebase.firestore();
exports.getTimeslots = functions.region('europe-west2').https.onCall((data, context) => {
const getData = async () => {
const uid = context.auth.uid;
let array = [];
if (!uid) {
throw new functions.https.HttpsError('no-userid', 'The requested user was not found');
} else {
const modulesRef = db.collection('users').doc(uid).collection('modules');
const modulesQuery = modulesRef.where('name', '!=', '');
const modulesQuerySnap = await modulesQuery.get();
const moduleDocuments = modulesQuerySnap.docs.map((doc) => ({ id: doc.id }));
for (const moduleDocument of moduleDocuments) {
const timeslotsRef = modulesRef.doc(moduleDocument.id).collection('timeslots');
const timeslotsQuery = timeslotsRef.where('length', '!=', -1);
const timeslotsQuerySnap = await timeslotsQuery.get();
const timeslotDocuments = timeslotsQuerySnap.docs.map((doc) => ({ id: doc.id, data: doc.data() }));
for (const timeslotDocument of timeslotDocuments) {
array.push(Object.assign(timeslotDocument.data, {id: timeslotDocument.id, modID: moduleDocument.id}))
}
}
return ({ data: array });
}
}
return getData()
.then((response) => {
// console.log(response);
return response;
});
}
The Reference page for Firestore reveals the docs property on the snapshot.
Upon running the code, here's the output:
{
data: [
{
length: 1,
id: '8UIlspnvelEkCUauZtWv',
modID: 'RmL5BWhKswEuMWytTIvZ'
},
{
title: 'Modules',
length: 120,
day: 1,
startTime: 720,
id: 'E5fjoGPyMswOeq8mDjz2',
modID: 'qa15lWTJMjkEvOU74N1j'
},
{
startTime: 360,
title: 'English',
day: 2,
length: 240,
id: '7JHtPSO83flO3nFOc0aE',
modID: 'qa15lWTJMjkEvOU74N1j'
}
]
}
This is a issue with how your function is written. Instead of
return ({ data: array });
Your function sometimes returns.
admin.firestore().collection('users').doc(uid).collection('modules').where('name', '!=', '').get()
Which is a promise by itself. You are chaining async inside then function. The solution is to make everything async await.
const data = await admin.firestore().collection('users').doc(uid).collection('modules').where('name', '!=', '').get()

I want to delete all the item but except of the current user

I am creating a call that deletes all the users except the current user logged in.
Here is my code;
exports.deletealluser = async (req, res) => {
try {
const { sub } = req.user;
const usersExceptCurrent = await User.find({ _id: !sub });
const deletedUsers = await User.deleteMany(usersExceptCurrent);
res.status(201).json({
message: 'A all user is successfully deleted!',
deletedUsers,
});
} catch (err) {
return res.status(400).json({
message: 'Something went wrong.',
});
}
};
sub is the id of the current user. As you can see, I call find query first to filter the data which is not equal to sub. Then I use the usersExceptCurrent as filter to my deleteMany query.
But it returns status 400
And here is my axios call;
const onDelete = async () => {
try {
const { data } = await fetchContext.authAxios.delete(
'admin/delete-all-users'
);
fetchContext.setUserList(
fetchContext.userList.filter((row) => row === data.deletedUsers)
);
setSignupSuccess(data.message);
setSignupError('');
setOpen(false);
setOpenAlert(false);
} catch (err) {
setIsLoaded(true);
setError(err);
const { data } = err.response;
setSignupError(data.message);
setSignupSuccess('');
}
};
Use $ne
$ne selects the documents where the value of the field is not equal to the specified value. This includes documents that do not contain the field.
db.collection.find({ _id: { $ne: sub } })
Demo - https://mongoplayground.net/p/ecMNn4ueZrn
If you still face for _id should be ObjectId you can do
const ObjectId = require("mongodb").ObjectId;
db.collection.find({ _id: { $ne: ObjectId(sub) } })
See what ! does, converts to bool value in JS
console.log(!"a");
console.log(!2);

Return inside map function is not working

I'm trying to get product details like price, discount by the id i'm getting from my cart. This return function is returning null. but working perfectly in console.log.
async function store (req,res) {
const item = req.session.cart;
const cart = new Cart(item);
const results = cart.generateArray();
let result = [];
result = results.map(item => {
Products.findOne({'_id': item.id}, function (err, r) {
if(err){
console.log(err);
} else {
return ({
product_id: r._id,
price: r.price,
qty: item.qty,
total: r.price*item.qty
});
// this return is not working
}
});
});
let data = await result;
return res.send(data);
}
You should use Promise.all to solve an array of promises:
result = results.map(async item => {
try {
const r = await Products.findOne({'_id': item.id})
return ({
product_id: r._id,
price: r.price,
qty: item.qty,
total: r.price*item.qty
});
} catch (err) {
console.log(err);
}
});
let data = await Promise.all(result);

Mongoose: Multi find() in forEach - Where is final then()

I use multi find() to populate 'categories' and 'pic' for 'post'. But I don't know Where is the data returned finally in full to 'res.send(posts)'.
Or use another method, 'Promise.all' for example, Please help me solve the problem
Post.find().then(posts=> {
async.forEach(posts, function(post, done) {
Cat.find().where('posts').in([post.id]).then(categories=> {
post.categories = categories;
var id=mongoose.Types.ObjectId(post.id);
File.findOne({'related.ref': id}).then(pic=>{
post.pic=pic;
});
})
//res.send(posts);????
});
});
You could use async-await for your route handler:
async (req, res) => {
const posts = await Post.find()
for (post of posts) {
const categories = await Cat.find().where('posts').in([ post.id ])
post.categories = categories
const id = mongoose.Types.ObjectId(post.id)
const pic = await File.findOne({ 'related.ref': id })
post.pic = pic
}
res.send(posts)
}

how can I wait for books data getting from graphql client in async function?

I want to wait for books data getting from graphql query before sending response object
async getUserBookList(req, res) {
let responseObj = {};
const validationRes = this.validateGetUserBookList(req);
const userId = req.params.id;
try {
const userBookList = await dbHelper.filterQuery(
{ user_id: userId },
"userbook"
);
const data = userBookList;
/**
* DESCRIPTION: Gets Books based on bookId
* PARAMS: _id!: string
* RETURNS: books: [Book]
*/
await userBookList.map(book => {
this.fastify.graphQLClient
.executeQuery({
query: books.userBooks({ _id: book.book_id })
})
.then(result => {
// => here the book is getting added
data["books"] = [result.data.books];
console.log(data);
});
});
res.send(data);
} catch (err) {
res.send(err);
}
}
I wanted to know what changes should I do ?? in the code so that response will contain "books" key
await userBookList.map(book => {
this.fastify.graphQLClient
.executeQuery({
query: books.userBooks({ _id: book.book_id })
})
.then(result => {
// => here the book is getting added
data["books"] = [result.data.books];
console.log(data);
});
});
You can use Promis.all with map.
const booksData = await BPromise.all(
userBookList.map( (book) =>
this.fastify.graphQLClient.executeQuery(
{
query: books.userBooks({ _id: book.book_id })
})
));

Resources