Duplicate item returned from collection - node.js

Blog Schema:
{
body: { type: String, required: true },
title: { type: String, required: true },
published: { type: String, default: false },
date: { type: Date, default: Date.now },
user: { type: Schema.Types.ObjectId, ref: 'BlogUser' },
comments: [{ type: Schema.Types.ObjectId, ref: 'Comments' }],
likes:[{user:{ type: Schema.Types.ObjectId, ref: 'BlogUser' }}]
}
Like Route for adding a like:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
await Blog.findByIdAndUpdate(
blog_id,
{
$push: {
likes: {
user: user_id,
},
},
},
{ new: true },
(err, newBlog) => {
if (err) res.status(422).json(err);
console.log(newBlog);
res.json(newBlog);
}
);
};
Blog Route for reciveing a blog:
exports.getBlogByID = async (req, res) => {
const blog_id = req.params.blog_id;
try {
const blog = await Blog.findById(blog_id)
.populate("comments")
.populate("user");
console.log(blog);
res.json(blog);
} catch (error) {
res.status(401).json(error);
}
};
When I add a like by calling Like route from client, I get a blog with correct amount of likes i.e only 1. But when I request blog from Blog Route it returns me with two objects inside "likes" array, with both same as each other(same id too). Why am I getting such result? Mind you that I call 'Blog Route' after calling 'Like Route'.

It worked fine after I changed "like route" to this:
exports.likeBlog = async (req, res) => {
const blog_id = req.params.blog_id;
const user_id = req.body.user_id;
const blog = await Blog.findById(blog_id);
blog.likes.unshift({ user: user_id });
await blog.save();
Blog.findById(blog_id)
.then((result) => {
res.json(result);
})
.catch((error) => {
res.status(501).json({ error });
});
};
I still don't know what's the difference between the two though.

Related

How do I update by using updteOne in mongodb?

router.post("/list/:shortId/recomment/:p_shortId", async (req, res, next) => {
const { shortId, p_shortId } = req.params;
const { comment } = req.body;
const email = req.tokenInfo.email;
try {
const authData = await User.findOne({email});
const postData = await Post.findOne({shortId});
const parentData = await Upment.findOne({p_shortId});
const newcomment = await Downment.create({
postType: 3,
author: authData,
post_id: postData,
parentment_id: parentData,
comment: comment
});
await Upment.updateOne({p_shortId}, {"$push": {"comments": newcomment._id}});
res.status(200).json({
result: 'recomment success'
})
} catch (err) {
err.message = `${err.message}, market post recomment error.`;
next(err);
}
});
updateOne doesn't work so I changed it to update
router.post("/list/:shortId/comment", async (req, res, next) => {
const { shortId } = req.params;
const { comment } = req.body;
const email = req.tokenInfo.email;
try {
const authData = await User.findOne({email});
const postData = await Post.findOne({shortId});
const newcomment = await Upment.create({
postType: 3,
author: authData,
post_id: postData,
comment: comment
});
// console.log(commentData);
await Post.updateOne({shortId}, {"$push": {"comments": newcomment._id}});
res.status(200).json({
result: 'comment success'
})
} catch (err) {
err.message = `${err.message}, market post comment error.`;
next(err);
}
});
then it worked. So I tried it in mongoDB Compass. like below
db.upments.updateOne({shortId: "wEhPg-wFqS0_2935vuZEQ"}, {"$push": {"comments": new ObjectId("62f38170e3dccbfe7a9842b2")}})
And this worked...
Only in the code, updateOne worked properly why this thing happens? how should I fix it?
thank you for listening question!!
here are schemas ^^ if you need anything more, let me know~
import mongoose from "mongoose"
import shortId from "./type/shortId.js"
const UpmentSchema = new mongoose.Schema({
shortId,
comment: String,
// closet:1, OOTD:2, board:3
postType: {
type: Number,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
post_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Post",
required: true
},
comments: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Downment",
}]
}, {
timestamps: true
}
);
const DownmentSchema = new mongoose.Schema({
shortId,
comment: String,
// closet:1, OOTD:2, board:3
postType: {
type: Number,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
post_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Post",
required: true
},
parentment_id: {
type : mongoose.Schema.Types.ObjectId,
ref: "Upment",
required: true
},
}, {
timestamps: true
}
);
export const Upment = mongoose.model("Upment", UpmentSchema);
export const Downment = mongoose.model("Downment", DownmentSchema);
It was an error in update({p_shortId})
p_shortId is not in the upment model
await Post.updateOne({shortId}, {"$push": {"comments": newcomment._id}});
my mistake ^^...

Mongodb find specific comment within array of objects in post collection

i store comments in post collection like this:
...
const postSchema = new mongoose.Schema(
{
body: {
type: String,
},
userId: {
type: String,
required: true,
},
likes: {
type: Array,
default: [],
},
img: {
type: String,
default: null,
},
comments: [
{
body: {
type: String,
required: true,
},
userId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
},
{ timestamps: true },
],
},
{ timestamps: true }
);
...
i created this put route to update comment:
app.put("/update-comment", (req, res) => {
posts.updateComment(req, res);
});
updateComment function:
const updateComment = async (req, res) => {
try {
const post = await Post.findById(req.body.postId);
const comment = await post.comments.map((commentObj) => {
return commentObj.find({ _id: req.body.commentId });
});
await comment.updateOne({ $set: req.body });
res.status(200).json(comment);
} catch (err) {
res.status(500).json(err);
}
};
it finds the post by postId and simply loop the comments array to find the comment object with the comment id provided, i tried this route with postman providing the following json body:
{
"postId":"6242a4c75bce78154824fc8f",
"commentId":"6242ac32a61fd275ed13846b",
"body":"my first comment updated"
}
but it doesn't work, it returns 500 internal error, if i replaced the code with this:
try {
const post = await Post.findById(req.body.postId);
const comment = post.comments;
res.status(200).json(comment);
} catch (err) {
res.status(500).json(err);
}
it will indeed return the comments within that post as an array of objects, i don't know what's wrong, i made sure the postId and commentId provided by the json body is correct, what's the problem?

How do I update nested array values in mongoose?

I am fairly new to nodejs/express and I'm practicing full stack development with devchallenges.io, i'm doing the shoppingify challenge. I'm trying to update the quantity of an item I am targeting inside of the items array. I understand my attempt below was terrible, I'm really struggling to understand the logic to be able to do so.
// #route PUT api/list/item/quantity/:id
// #desc Increase or decrease quantity
// #access Private
router.put('/item/quantity/:id', auth, async (req, res) => {
const { action } = req.body;
try {
let list = await List.findOne({ user: req.user.id });
const item = list.items.find(
(item) => item._id.toString() === req.params.id
);
list = list.updateOne(
{ 'items._id': req.params.id },
{ $set: { 'items.quantity': item.quantity + 1 } }
);
await list.save();
return res.json(list);
} catch (error) {
console.error(error.message);
res.status(500).send('Server Error');
}
});
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ListSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
},
name: {
type: String,
default: 'Shopping List',
},
items: [
{
name: {
type: String,
default: '',
},
note: {
type: String,
default: '',
},
image: {
type: String,
default: '',
},
category: {
type: String,
default: '',
},
quantity: {
type: Number,
default: 1,
},
},
],
date: {
type: Date,
default: Date.now,
},
});
module.exports = List = mongoose.model('list', ListSchema);
Look this is my update-vendor route here I'm updating nested street and city name.
router.put("/update-vendors", async (req, res, next) => {
const vendor = await Vendor.updateOne(
{
"address.street": "Street2",
},
{
$set: {
"address.$.street": req.body.street,
"address.$.city": req.body.city,
},
}
);
res.status(200).json(vendor);
});
You can update particular things with the help of $set and other $push method

How to delete comment that is nested in Post schema with mongoose and nodejs?

I want to be able to delete comment that is inside my Post model.
This is my Schema for Post model:
const PostSchema = new Schema({
userID: {
type: Schema.Types.ObjectId,
ref: 'user'
},
content: {
type: String,
required: true
},
registration_date: {
type: Date,
default: Date.now
},
likes: [
{
type: Schema.Types.ObjectId,
ref: "user"
}
],
comments: [
{
text: String,
userID: {
type: Schema.Types.ObjectId,
ref: 'user'
}
}
]
})
And I have this route:
router.delete('/comment/:id/:comment_id', auth, async (req, res) => {
const postId = req.params.id
const commentId = req.params.comment_id
}
comments in post looks like this:
comments: [
{
_id: 5f1df4cf5fd7d83ec0a8afd8,
text: 'comment 1',
userID: 5efb2296ca33ba3d981398ff
},
{
_id: 5f1df4d35fd7d83ec0a8afd9,
text: 'commnet 2',
userID: 5efb2296ca33ba3d981398ff
}
]
I want to delete comment, and don't know how to do it. Does anyone have idea how to do it?
First we find the post by findByIdAndUpdate then we delete the comment using $pull from the array of comments.
router.delete("/comment/:id/:comment_/id", async function (req, res) {
try {
const post = await Post.findByIdAndUpdate(
req.params.id,
{
$pull: { comments: {_id:req.params.comment_id}},
},
{ new: true }
);
if (!post) {
return res.status(400).send("Post not found");
}
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});

Unable to populate nested schema reference in Mongoose

I have multiple Schemas and I'm trying to query the data using populate. I'm using mongoose(5.9.7) and express js.
First Schema - ProfileSchema
const ProfileSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
jobs: [
{
type: Schema.Types.ObjectId,
ref: "Job"
}
],
resumes: [
{
type: Schema.Types.ObjectId,
ref: "Resume"
}
],
name: {
type: String,
required: true
},
});
module.exports = Profile = mongoose.model("Profile", ProfileSchema);
Second Schema - Resume Schema
const ResumeSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: "User"
},
fileLink: { type: String, required: true },
fileName: { type: String, required: true },
description: { type: String, required: true }
});
module.exports = Resume = mongoose.model("Resume", ResumeSchema);
Route
router.get(
"/",
passport.authenticate("jwt", { session: false }),
async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.user.id
})
.populate("resumes")
.exec();
res.json(profile);
} catch (error) {
return res.status(400).json(error);
}
}
);
This returns an empty array for both resume and jobs. I have tried different variations of populate but it doesn't work. Tried deeppopulate as well. Though User gets populated fine.
EDIT: Adding resume upload route
Route
router.post(
"/upload",
passport.authenticate("jwt", { session: false }),
upload.single("resume"),
async (req, res) => {
try {
// upload to s3 code here
if (data) {
const resumeData = {
description: req.body.description,
fileName: params.Key,
fileLink: data.Location,
user: req.user.id
};
const resume = new Resume(resumeData);
const fileSavedToSchema = await resume.save();
return res.json(fileSavedToSchema);
}
} catch (error) {
console.log(error);
}
}
);
I'm able to view the resumes using a different route.

Resources