Mongodb find specific comment within array of objects in post collection - node.js

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?

Related

Mongoose - findByIdAndUpdate

All,
I can seem to figure out why the record in the database will not update. I am not 100% sure where my error is but this isn't really providing me a great error message. Can someone please take a look at this for me?
I believe that I am calling the mongoose request properly. Thank you in advance!
$ npm mongoose -v
8.15.0
const mongoose = require("mongoose");
const CartSchema = new mongoose.Schema(
{
owner: {
type: String,
unique: true,
required: true,
},
discount: {
type: Number,
},
total: {
type: Number,
},
items: [
{
itemId: {
type: Number,
},
sku: {
type: Number,
},
quantity: {
type: Number,
},
price: {
type: Number,
},
},
],
},
{ timestamps: true }
);
const Cart = mongoose.model("Cart", CartSchema);
module.exports = Cart;
Record in Database
{"_id":{"$oid":"630689708997a6589635986c"},
"owner":"611afa8b9069c9126cff3357",
"total":{"$numberInt":"0"},
"items":[],
"createdAt":{"$date":{"$numberLong":"1661372784844"}},
"updatedAt":{"$date":{"$numberLong":"1661372784844"}},
"__v":{"$numberInt":"0"}}
exports.add = async (req, res, next) => {
const { id, product } = req.body;
const addItem = { itemId: product._id, sku: product.sku, quantity: 1, price: product.price };
console.log(addItem);
try {
const updateCart = Cart.findByIdAndUpdate(id, { $addToSet: { items: addItem } }, { new: true, returnDocument: "after" });
if (!updateCart) return next(new ErrorResponse("Unable to update the cart record", 404));
console.log(updateCart);
if (updateCart) {
return sendRes(updateCart, 200, res);
} else {
return sendRes(updateCart, 201, res);
}
} catch (error) {
console.log(error);
next(error);
}
};
This issue was caused by me using an ASYNC Function without the AWAIT on the DB Call.
Please try once with this:
Cart.findByIdAndUpdate(id, { $addToSet: { items: addItem } }, { new: true, returnDocument: "after" });
The first obvious mistake is that you're searching for a document with the wrong field:"id", Kindly change that to "_id: id"
Also you might need to convert the _id string you have to MongoDB Object ID, like this:
const ObjectId = require('mongodb').ObjectId;
Cart.updateOne({_id: new ObjectId(id)}, { $addToSet: { items: addItem } }, { new: true, returnDocument: "after" });
For other update method, you need to specify the field, and also convert it to a MongoDB ID
OR
Cart.findByIdAndUpdate(id, { $addToSet: { items: addItem } }, { new: true, returnDocument: "after" })
You do not to specify the field in findByIdAndUpdate, just pass the id to it.

Mongoose don't insert object into array

I have a simple express application that insets comments into posts, the issue is that the comments are never inserted but no errors are shown when post via postman it properly returns the post but with no comments.
Just try: this and this but seems to not working
This is my schema
interface PostAttrs {
userid: mongoose.Schema.Types.ObjectId;
username: string;
date: Date;
text: string;
image: string;
comments: Array<any>;
likes?: number;
}
const postSchema = new Schema<PostAttrs>({
userid: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
username: {
type: String,
required: true,
},
date: {
type: Date,
required: true,
},
text: {
type: String,
required: true,
},
image: {
type: String,
required: false,
},
comments: [
{
required: false,
date: {
type: String,
required: true,
},
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
text: {
type: String,
required: true,
},
},
],
likes: {
type: Number,
required: true,
},
});
And the API route
export const createComment = async (req: Request, res: Response) => {
try {
const postId = req.params.postId;
const userId = req.params.userId;
const comment = req.body.comment;
var commentObj = {
date: new Date(),
userId: userId,
text: comment
};
await Post.findOneAndUpdate(
{ _id: postId },
{ new: true },
{$push: {
comments: { commentObj }
}},
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
}
);
} catch (error) { }
}
What's wrong with my code?
SOLVED: The problem was the order of the parameters in the findOneAndUpdate() sentence, first the search condition, next, the value to update, and finally the statement. So I had to change this
await Post.findOneAndUpdate(
{ _id: postId },
{ new: true },
{$push: {
comments: { commentObj }
}},
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
});
to
await Post.findOneAndUpdate(
{ _id: postId },
{$push: {
comments: { commentObj }
}},
{ new: true },
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
});
When using 'await' with Mongoose's methods like findOneAnd.... the method is not run unless you explicitly do so.
Try:
await Post.findOneAndUpdate(......).exec();
Also when using the await keyword you can refactor and remove the callbacks

updating document inside array in mongoose

I want to update my answer object inside answers array. I am using following schema
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const questionSchema = new mongoose.Schema(
{
postedBy: {
type: ObjectId,
required: true,
ref: "User",
},
question: {
type: String,
required: true,
},
photo: {
data: String,
required: false,
},
answers: [
{
userId: { type: ObjectId, ref: "User" },
answer: String,
},
],
questionType: {
data: String,
required: false,
},
},
{ timeStamps: true }
);
module.exports = mongoose.model("Question", questionSchema);
I am using updateOne method to update my answer in my db. Can anyone explain what is missing here. I am been trying to solve this since hours
exports.updateAnswer = (req, res) => {
const questionId = req.body.questionId;
const answerId = req.body.answerId;
Question.findOne({ _id: questionId }).exec((err, question) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
return;
}
if (!question) {
res.status(400).json({
error: "question not found",
});
return;
}
});
Question.updateOne(
{ _id: answerId },
{
$set: {
"answers.$.answer": "This is update answer. My name is Ravi Dubey",
},
},
{ new: true },
(err, success) => {
if (err) {
res.status(400).json({
error: errorHandler(err),
});
}
res.json({
msg: "answer updated successfully",
success,
});
}
);
};
My result is coming successful but answer is not updating in db.
I am confused on Question.updateOne method.
Any help appreciated.
If you trying to query based on id of one of the documents in the answers array then instead of {_id: answerId} you need to provide {'answers._id': answerId}. And also if you need the updated document as result then you should use the findOneAndUpdate method.
Question.findOneAndUpdate(
{ "answers._id": answerId },
{ $set: { "answers.$.answer": "some answer" } },
{ new: true },
(err, data) => {
// handle response
}
);

Is there a way i could keep track of the Time and the entity that was changed in a model

Basically I'm trying to get the time and the entity changed in a particular model when ever the update method is called.
This is my model I want to keep track of:
const mongoose = require("mongoose");
const modelSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
name: {
type: String,
required: true,
},
note1: String,
note2: String,
note3: String,
images: {
type: Array,
required: true
},
status: {
enum: ['draft', 'pending_quote', 'pendong_payment', 'in_production', 'in_repair', 'pemding_my_review', 'fulfilled'],
type: String,
default: "draft"
},
price: {
type: mongoose.Schema.Types.ObjectId,
ref: "Price",
}
}, {
timestamps: true,
})
module.exports = mongoose.model("Model", modelSchema)
And this is the method I call to update the status:
exports.updateModel = async (req, res) => {
try {
let id = req.params.id;
let response = await Model.findByIdAndUpdate(id, req.body, {
new: true
})
res.status(200).json({
status: "Success",
data: response
})
} catch (err) {
res.status(500).json({
error: err,
msg: "Something Went Wrong"
})
}
}
you can add a new field in your schema like:
logs:[{
entity: String,
timeStamp: Date
}]
Then updating it basing on your current code:
let id = req.params.id;
// I don't know whats in the req.body but assuming that it
// has the correct structure when passed from the front end
let response = await Model.findByIdAndUpdate(id,
{
$set:req.body,
$push:{logs:{entity:'your entity name here',timeStamp:new Date()}}
}, {
new: true
})

Duplicate item returned from collection

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.

Resources