mongodb find all slow - node.js

I'm new with nodejs and mongodb. I have a simple request which will return 800 entities without any where statements. Just find all. or explain();
Very slow responder.....
Is there a more better way to do collection.find().lean() ?
const Jobs = require("../model/Jobs.mongo");
const saveData = async (title, link, location, idJob, companyName) => {
const found = await Jobs.findOne({ idJob: idJob });
if (!found) {
try {
const job = new Jobs({
title: title,
link: link,
location: location,
idJob: idJob,
companyName: companyName,
});
await job.save();
console.log(job);
} catch (e) {
console.log(e);
}
} else {
console.log(`${title} ***** is already in the data with id ***** ${idJob}`);
}
};
const getAllJobs = async (req, res) => {
const jobs = await Jobs.find({}).sort({ createdAt: "desc" }).lean();
res.status(200).json({ jobs, count: jobs.length });
};
const getJobByCompany = async (req, res) => {
const {
params: { companyName: companyName },
} = req;
const job = await Jobs.find({
companyName: companyName,
});
if (!job) {
res.status(404).json({});
}
res.status(200).json({ job, count: job.length });
};
module.exports = {
saveData,
getAllJobs,
getJobByCompany,
};

If you are facing this issue for a while try to check you internet connection.
You can also take a look how much is the data that you want to receive.
It can be just from a internet speed drop, let me know what is the result :)

Related

Path `comment` is required. MERN stack

I don't understand why I get this error. This is my controller:
export const createProductReview = async (req, res) => {
const { rating, comment } = req.body;
const product = await Product.findById(req.params.id);
if (product) {
const alreadyReviewed = product.reviews.find(
r => r.user.toString() === req.user.userId.toString()
);
if (alreadyReviewed) {
throw new NotFoundError('Product already reviewed');
}
const review = {
user: req.user.userId,
name: req.user.username,
rating: Number(rating),
comment,
};
product.reviews.push(review);
product.numOfReviews = product.reviews.length;
product.rating =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
await product.save();
res.status(StatusCodes.OK).json({ message: 'Review added', review });
} else {
throw new NotFoundError('Product not found');
}
};
This is mine productPage where i dispatch addProductReview and passing product id from params and review object:
const [rating, setRating] = useState(0);
const [comment, setComment] = useState('');
const submitHandler = e => {
e.preventDefault();
dispatch(
addProductReview(id, {
rating,
comment,
})
);
};
And this is my productSlice:
export const addProductReview = createAsyncThunk(
'product/review',
async (id, { review }, thunkAPI) => {
try {
const { data } = await axios.post(
`/api/v1/products/${id}/reviews`,
review
);
return data;
} catch (error) {
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
);
I have no clue why i got error Path comment is required. i pass review object to route.
The issue is with the parameters used in your Thunk payloadCreator. From the documentation...
The payloadCreator function will be called with two arguments:
arg: a single value, containing the first parameter that was passed to the thunk action creator when it was dispatched. This is useful for passing in values like item IDs that may be needed as part of the request. If you need to pass in multiple values, pass them together in an object when you dispatch the thunk, like dispatch(fetchUsers({status: 'active', sortBy: 'name'})).
thunkAPI: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options
Your payloadCreator has three arguments which is incorrect.
Try this instead
export const addProductReview = createAsyncThunk(
'product/review',
async ({ id, ...review }, thunkAPI) => {
try {
const { data } = await axios.post(
`/api/v1/products/${id}/reviews`,
review
);
return data;
} catch (error) {
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
);
and dispatch it like this
dispatch(addProductReview({ id, rating, comment }));

Response returned as null for Nested mongodb queries from Node JS + React

I have a an api call handler coded out like this in Node JS + Express.
const express = require("express");
const router = express.Router();
const PostModel = require("../models/postModel");
const ProfileModel = require("../models/profileModel");
const multer = require("multer");
const fs = require("fs");
const path = require("path");
const uuid = require("uuid");
//please ignore unused dependencies because im using them in other api call handlers
router.post('/get-posts/', (req, res) => {
const { userId } = req.body;
PostModel.find((err, postData) => {
if(err){
return res.send({
success: "False",
message: "Error while getting posts"
});
}
const data = [];
postData.forEach(async (p, index) => {
const b64 = Buffer.from(p.post.image.data).toString('base64');
const mimeType = p.post.image.contentType;
const url = `data:${mimeType};base64,${b64}`;
var ddd = await ProfileModel.findOne({
userId: p.authorId
}, async (e, d) => {
if(e){
console.log(e);
}
}).clone();
let dpMimeType = ddd.profilePic.contentType;
let dpUrl = `data:${dpMimeType};base64,${b64}`;
const obj = {
authorId: p.authorId,
postId: p.postId,
dp: dpUrl,
post: {
authorName: p.post.authorName,
creationDate: p.post.creationDate,
heading: p.post.heading,
image: url,
message: p.post.message,
likes: p.post.likes,
dislikes: p.post.dislikes,
hearts: p.post.hearts,
comments: p.post.comments,
likedUsers: p.post.likedUsers,
dislikedUsers: p.post.dislikedUsers,
heartedUsers: p.post.heartedUsers
}
};
data.push(obj);
});
if(postData.length > 0){
return res.status(200).send({
posts: data
});
} else {
return res.status(200).send({
message: "No posts found for this user"
});
}
});
});
Now what Im doing here is Im fetching all posts from the PostModel from the db. Then I iterate over each of those posts, then query that post's authorId and pass it to the ProfileModel to get back the author's dp, attach it to my response body and send it back to my React frontend frm where I can access the same and display the author's dp along with the author's post.
But the problem that occurs here is that, Im getting the following response from the api call:-
{"posts":[]}
that is, a blank response is returned. But there is no errors logged out anywhere neither does my node server break due to some errors. It runs smoothly, but there is no response returned inspite of the fact that there are enough documents in both the collections in the db. So its not a problem of the db being empty.
I have no idea what to do. Any and all help is massively appreciated.
forEach is not meant to be used with async await, try with this logic:
router.post('/get-posts/', async (req, res) => {
try {
const { userId } = req.body;
const postData = await PostModel.find({});
if (postData.length === 0) {
return res.status(400).send({
message: 'No posts found for this user',
});
}
const data = [];
for (const p of postData) {
const b64 = Buffer.from(p.post.image.data).toString('base64');
const mimeType = p.post.image.contentType;
const url = `data:${mimeType};base64,${b64}`;
var ddd = await ProfileModel.findOne({
userId: p.authorId,
});
let dpMimeType = ddd.profilePic.contentType;
let dpUrl = `data:${dpMimeType};base64,${b64}`;
const obj = {
authorId: p.authorId,
postId: p.postId,
dp: dpUrl,
post: {
authorName: p.post.authorName,
creationDate: p.post.creationDate,
heading: p.post.heading,
image: url,
message: p.post.message,
likes: p.post.likes,
dislikes: p.post.dislikes,
hearts: p.post.hearts,
comments: p.post.comments,
likedUsers: p.post.likedUsers,
dislikedUsers: p.post.dislikedUsers,
heartedUsers: p.post.heartedUsers,
},
};
data.push(obj);
}
return res.status(200).send({
posts: data,
});
} catch (err) {
res.status(500).send({
success: 'False',
message: 'Error while getting posts',
});
}
});

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()

Why is my graphql apollo resolver not being called?

I'm pretty new to graphql (and nodejs as well). I'm following a Udemy course on Apollo and mongo which has been going well mostly. However I can't get one of the resolvers to be called. Another resolver is working fine, and they appear to use the same layout. Also, the context is being called before the resolver that is not being called, so I know it's at least getting that far.
Here is the root server.js with the working context:
const resolvers = require('./resolvers');
...
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
await verifyUser(req);
console.log("=== context ran, user email : ", req.email) ;
return {
email: req.email,
loggedInUserId: req.loggedInUserId
}
}
});
resolvers are modularized, and combined in a /resolvers/index.js, here:
const { GraphQLDateTime } = require('graphql-iso-date')
const userResolver = require('./user');
const taskResolver = require('./task');
const customDateScalarResolver = {
Date: GraphQLDateTime
}
module.exports = [
userResolver,
taskResolver,
customDateScalarResolver
]
and here is the tasks resolver, located at /resolvers/task.js, which is the one not being called:
const uuid = require('uuid')
const { combineResolvers } = require('graphql-resolvers');
const { users, tasks } = require('../constants');
const Task = require('../database/models/task');
const User = require('../database/models/user');
const { isAuthenticated, isTaskOwner } = require('./middleware');
module.exports = {
Query: {
tasks: async ( _, __, { loggedInUserId }) => {
console.log("tasks query, loggedInUserId : ", loggedInUserId);
try {
const tasks = await Task.find( { user: loggedInUserId });
return tasks;
} catch (error) {
console.log(error);
throw error;
}
},
task: async ( parent, { id }, ) => {
console.log("taskbyId query, id : ", id);
// tasks.find(task => task.id == args.id);
try {
const task = await Task.findById(id);
console.log("taskById query, found task? : ", task);
return task;
} catch (error) {
console.log(error);
throw error;
}
},
},
Mutation: {
// createTask: combineResolvers(isAuthenticated, async (_, { input }, { email }) => {
createTask: async (_, { input }, { email }) => {
try {
console.log("creating task, email : ", email);
const user = await User.findOne({ email });
const task = new Task({ ...input, user: user.id });
const result = await task.save();
user.tasks.push(result.id);
await user.save();
return result;
} catch (error) {
console.log(error);
throw error;
}
}
// )
},
Task: {
user: async ( parent ) => {
console.log("in task.user field resolver");
try {
const user = await User.findById(parent.user);
return user;
} catch (error) {
console.log(error);
throw error;
}
}
},
}
When I run the tasks query, the console.log from the context setup function logs 3 times, but does NOT log the console.log line from the tasks resolver. It also appears to not return at all. I'm just using the default graphiql web client. The verifyUser() does find a return a user, so I know the db connection is working fine as well.
mergeResolvers should be used to merge resolvers.
It's designed to merge different [entities] object [/structured] resolvers before use [as one tree structured] in server [config].
F.e. it merges/combines respectively [by type] Query resolvers from users resolver with tasks Query resolvers ... and Mutation resolvers from users resolver with tasks Mutation resolvers.

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