How would I properly set a new variable for a json object? - javascript

In Node JS I have an endpoint where I am trying to get data from two different mongo collections and when trying to piece the data together I am not able to add another property to the JSON object.
const getLessonWithTopics = async (req, res) => {
const lessonId = req.params.id;
// Get the lesson
Lesson.findOne({_id: lessonId}).exec((err, data) => {
let lesson = data;
Topic.find().where('_id').in(data.topics).exec((err, topics) => {
if(err) res.status(500).send("Error something went wrong");
lesson.associatedTopics = topics;
console.log(lesson);
res.json(lesson)
})
})
}
When logging lesson to console it does not have the associatedTopics property even though through searching online I have found multiple instances where some is saying this is how you would add this property. (Ex. Add new attribute (element) to JSON object using JavaScript )
I have tried using var as well, to see if that would change something (maybe make it mutable) it did not.
** When logging the topics object to console it does log the data that I expected so the variable 'topics' is not the issue **
I'm sure that it is something simple that I am missing and hoping someone with a large brain can help figure this out for me.
Any help would be appreciated, Thank you!

Can you try once with the following code?
const getLessonWithTopics = async (req, res) => {
const lessonId = req.params.id;
// Get the lesson
try {
const lession = await Lession.findOne({ _id: lessonId }).lean()
const topics = await Topic.find({ _id: { $in: lession.topics } }).lean()
lession.associatedTopics = topics
res.json(lesson);
} catch (err) {
console.log(err)
res.status(500)
}

Related

how sort with mongoose

I have a little question
I try to sort with mongoose I know the simple way
but I dont know how to do that with data I get in req.body lets say.
I add here a code I try
exports.sortBy = async (req, res, next) => {
const data1 = req.body.data1 //the data i want to sort
const sortBy = req.body.sortBy //sory by price,createdAt,length and more
const downUp = req.body.downUp // 1, -1
console.log(sortBy)
console.log(data1)
const data = await Book.aggregate([
{
$sort: { [sortBy]: downUp }
},
])
res.status(200).json({
status: 'success',
results: data.length,
data
})
}
so I can sort by the data I get in req.body
Try the following:
const data = await Book.sort({sortBy: downUp});
which seems to work and is much easier to read.

Using express-session variable as type array

I am creating an e-commerce type site with shopping cart functionality.
When a Customer adds product to cart, I need to add the data of the product into an array in the session variable.
I tried like this:
router.post('/addtocart', authCheck.login, async(req, res) => {
// console.log(req.body)
req.session.cart = []
let doc = {
...req.body
}
await req.session.cart.push(doc)
console.log(req.session.cart)
What happens is each time a product is added to the cart, it doesn't keep the existing data in there. So if I go to add two products, only the latest one shows in there. How can I fix this?
To explain your problem: the req.session.cart = [] code is emptying your req.session.cart data by passing it a value of empty array = [] every time your /addtocart endpoint is triggered.
A solution would be:
router.post('/addtocart', authCheck.login, async(req, res) => {
// req.session.cart = []
let updatedCart = []
let { cart } = req.session
let doc = {
...req.body
}
// await req.session.cart.push(doc) //await is unnecessary here
updatedCart.push(...cart, doc)
req.session.cart = updatedCart
console.log("req.session.cart: ", req.session.cart)
You can read more about the await keyword at MDN documentations - await.
Let me know if you have any other question.

save method in mongodb/mongoose

This is my first question here. I tried to save document in my collection, but it doesn't work. Response of function is exactly like I want, but it doesn't save in my db. In another controller (createRoom) foundUser.save() it works, but in this controller it doesn't. Thanks in advance!
I am using mongodb/mongooose and express.
const removeRoom = async (req,res,next) => {
const {roomId, userData} = req.body;
const { userId, token } = userData;
let foundUser;
let updatedRooms;
let indexOfNamespaces;
try {
foundUser = await User.findById(userId)
foundUser.namespaces.forEach((ns,i1)=>{
updatedRooms = ns.rooms.filter((room,i2) => {
if(room.id === roomId){
indexOfNamespaces = i1;
}
return room.id !== roomId
})
})
foundUser.namespaces[indexOfNamespaces].rooms = updatedRooms;
console.log(foundUser);
await foundUser.save();
} catch (err) {
console.log(err);
const error = new HttpError('Sth went wrong [removeRoom]', 500);
return next(error);
}
res.status(201).json({updatedNamespaces: foundUser.namespaces});
}
Mongoose does some optimizations where it will only actually save a field if it "changes". In this case you are modifyting an array, but the array is still the "same" array as in it still === (equals) the previous array. You need to use a new array to replace namespaces.
For example:
foundUser.namespaces = [
...foundUser.namespaces.slice(0, indexOfNamespaces),
{ ...foundUser.namespaces[indexOfNamespaces], rooms: updatedRooms },
...foundUser.namespaces.slice(indexOfNamespaces + 1)
]
Now, when you save Mongoose will see a "new" array that !== (does not equal) the previous array because it is a new instance and it will save it.

check if object in array of objects - javascript

I know i have to use some but for some reason i cant seem to get it right. i have a collection in my mongodb database of posts. each post has an array of objects named "likes" that references the users that liked this post. so in my backend i want to check if the user exists in the likes array of the post. if it does not exist then like the post, else return with an appropriate message on my react frontend. The code i will include always returns false from some so a user can like a post infinite times.
exports.postLike = async (req, res, next) => {
const postId = req.query.postId;
const userId = req.query.userId;
console.log('postId: ' + postId);
try{
const post = await Post.findById(postId).populate('creator').populate('likes');
const user = await User.findById(userId);
if (!post.likes.some(post => post._id === user._id)){
post.likes.push(user);
console.log('liked a post');
const result = await post.save();
res.status(200).json({ message: 'Post liked!', post: result });
} else {
console.log('Post already liked!');
res.status(200).json({ message: 'Post already liked!', post: post });
}
}catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
i clearly haven't understood, yet, how some works so if you can help that would be great. also if you have any other solution that would be good in this case then please post it. i tried some random codes with indexOf and includes for checking but it didn't work either. i am not sure which is the right way to check if the user object is included in the "likes" array of objects. i would prefer not to write any function of my own to check this, i want to do it using an existing function/method provided by javascript.
Going to offer a different route here. You are fetching all the data including a join to the creator and likes just to add a like to the collection. This is a little wasteful and can be achieved by just doing an update and use $addToSet which will add the like if it does not exist.
You then just check nModified in the result to know if it was added or not. So you can have:
const result = await Post.updateOne(
{
id: 1
},
{
$addToSet: {
likes: {
userId: mongoose.Types.ObjectId(req.query.userId)
}
}
}
);
console.info(result.nModified === 1);
Alternatively, you can use some as follows using === to compare type and value:
posts.likes.some(like => like.userId.toString() === req.query.userId)
MongoDB.ObjectId is a wrapper around a primitve, just like Number or Boolean. And just like
new Boolean(true) === new Boolean(true)
will be false, your comparison will fail too. You have to take out the primitive for comparison:
post._id.valueOf() === user._id.valueOf()

How do I return an array of documents using an array of users object ids in mongoose?

I am trying to create a simple back end blog api with user authentication and authorization. It is built with mongoose and express. In my userSchema, I have a property that is an array called "subscribedTo". Here, users can subscribe to different users to get their blogs. The subscribedTo array stores objectIDs of the users that wished to be subscribed too.
Here is my code:
router.get('/blogs', auth, async (req, res) => {
//auth middleware attaches user to the request obj
try {
let blogs = []
req.user.subscribedTo.forEach(async (id) => {
let ownersBlogs = await Blog.find({owner:id})
blogs = [...blogs, ...ownersBlogs]
console.log(blogs)//consoles desired output of users blogs
})
console.log(blogs)//runs first and returns []
res.send(blogs)
}catch(e){
res.status(500).send(e)
}
})
When I use postman for this route it returns [] which is understandable. I can't seem to res.send(blogs) even though the blogs variable returns correctly in the forEach function.
Is there a better way to do this?
You can use without loop like as bellow
Blog.find({ owner: { $in: req.user.subscribedTo } }, function (err, blogResult) {
if (err) {
response.send(err);
} else {
response.send(blogResult);
}
});
OR
send response after loop completed like as bellow
router.get('/blogs', auth, async (req, res) => {
//auth middleware attaches user to the request obj
try {
let blogs = []
let len = req.user.subscribedTo.length;
let i = 0;
if (len > 0) {
req.user.subscribedTo.forEach(async (id) => {
let ownersBlogs = await Blog.find({ owner: id })
blogs = [...blogs, ...ownersBlogs]
console.log(blogs)//consoles desired output of users blogs
i++;
if (i === len) {
//send response when loop reached at the end
res.send(blogs)
}
})
} else {
res.send(blogs);
}
} catch (e) {
res.status(500).send(e)
}
});
You can find all the documents without a foreach loop, use $in
Blog.find({owner:{$in:[array of ids]}});

Categories

Resources