Mongoose update subdocument - node.js

I have some posts documents which contains an array of ids of comments. I am trying to update a particular comment based on the post and the comment id and not sure how to go about it. I have tried to use the $set command but I think I missed something and It doesn't work. What I have tried doing.
async function updateComment(req, res){
try{
const post = await PostsModel.findOneAndUpdate(
{"postID": req.params.id, "comments.id": req.params.commentID},
{"$set": {
"comments.$": req.body
}}
).populate("comments");
if (!post){
return res.status(404).json({msg: "No post found"});
}
res.status(200).json({post});
}catch (e) {
res.status(500).json(e.message);
}
}
The structure and schema of the document:
{
"_id": "62b2c3d0e88f58ddd1135bc7",
"title": "aaaa",
"content": "check it out",
"createdAt": "2022-06-22T07:23:34.525Z",
"comments": [
"62b2fe23b15d50b496149128"
],
"postID": 1
}
The schema for both the post and comment:
const CommentSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
content:{
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
})
const PostsSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
createdAt:{
type: Date,
default: new Date()
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});

Related

Updating array of objects inside an object mongodb node

I have a mongoDb model defined as follows:-
var mongoose = require("mongoose");
const postModel = new mongoose.Schema({
postId: {
type: String,
unique: true,
required: true
},
authorId: {
type: String,
required: true
},
post: {
authorHandle: {
type: String,
required: true
},
heading: {
type: String,
required: true
},
message: {
type: String,
required: true
},
creationDate: {
type: Date,
required: true
},
image: { type: Array },
video: { type: Array },
comments: {
type: Array
}
}
});
module.exports = mongoose.model("postModel", postModel);
Now I have a sample value of a document of the above model, suppose:-
postId: "aaa",
authorId: "bbb",
post: {
authorHandle: "someone#123",
heading: "hello",
message: "post 1",
creationDate: "some creation date string(please ignore this is irrelevant to my question)",
image: [],
video: [],
comments: [
{ commentId: "1", message: "Something", createdAt: sometime },
{ commentId: "2", message: "Something else", createdAt: sometime2 },
{ commentId: "3", message: "Something other", createdAt: sometime3 },
]
}
Now say the user wants to update the comment with commentId 2 of this post with postId "aaa". My question is that what is the best way to use the findOneAndUpdate() method to solve this problem?
const PostModel = require("./models/PostModel"); //just importing the model that is defined above
//the below is happening inside a request handler in Node + Express
PostModel.findOneAndUpdate(
//what to do here
)
What I have tried is pulling out that whole object and replacing it with a new object with the new message. But that doesnt seem like a very efficient way. Any and all help is greatly appreciated!
You should write:
const updatedPost = await PostModel.findOneAndUpdate(
{ postId: 'aaa', 'post.comments.commentId': 2 },
{ 'post.comments.$.message': 'Updated message'},
{ new: true }
)

Display data from another collection in MongoDB

I have two separate collection in MongoDB 1-> Post, 2-> Comment.
Post-schema:
const postSchema = new mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
media: {
type: [mongoose.Schema.Types.Mixed],
trim: true,
required: true,
},
text: String,
mentions: {
type: Array,
default: [],
},
hashTags: {
type: ["String"],
},
likes: {
type: Array,
default: [],
},
postStatus: {
type: "String",
default: "public",
enum: ["public", "private"],
},
deletedAt: {
type: "Date",
default: null,
},
},
{ timestamps: true }
);
comment schema:
const commentSchema = new mongoose.Schema(
{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
postId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Post",
required: true,
},
commentText: String,
},
{ timestamps: true }
);
Now I want to display all the comments of requested post. Post table does not have anything that links to Comment that is why I can not use populate(). but Comment table have postId to connect.
Here's what I have tried:
exports.getPostById = async (req, res) => {
try {
let post = await Post.findById(req.params.id);
if (!post) return res.status(404).json({ message: "No Post found" });
let comment = await Comment.find({ postId: { $in: {post: req.params.id} } });//Wrong query
return res.status(200).send(post);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
Use lookup in an aggregation query.
please refer to this link.
https://www.mongodb.com/docs/manual/reference/operator/aggregation/lookup/
example:
db.post.aggregate([{
$lookup: {
from: ‘comment’,
localField: ‘user_id’,
foreignField: ‘user_id’,
as: ‘whatever_name_you_want’
}}]);
Try this:
Transform the id string from params to a ObjectId:
let postObjectId = mongoose.Types.ObjectId(req.params.id);
Query using the variable defined above:
let comments = await Comment.find({ postId: postObjectId});

POPULATION ISSUE: Mongoose/Express

I'm trying to have each record attached to a user who created it,
and every user have their records attached.
Here are my schemas:
1.The Records schema:
const mongoose = require('mongoose')
const RecordsSchema = new mongoose.Schema(
{
Title: { type: String, required: true },
postedby:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
}],
Author: { type: String, required: true},
ISBN: { type: String, required: true },
Review: { type: String },
SelectedFile: { type: String },
Likes: { type: Number, default:0},
Date: { type: Date, default: Date.now()}
});
module.exports = Records = mongoose.model('record', RecordsSchema', 'record');`
Here is the The user Schema:
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema(
{
username: { type: String},
email: { type: String, required: true ,unique:true},
records:[{
type: [mongoose.Schema.Types.ObjectId],
ref: 'record' }],
password: { type: String, required: true},
Date: { type: Date, default: Date.now(), immutable: true }
});
module.exports = User = mongoose.model('user', userSchema,'user');
The express route for getting a record:
router.get('/postedby/', (req, res) => {
Records.find(req.params.id)
.populate('postedby')
.exec()
.then(post =>{
if (!post) {
return res.status(400).json({ msg: 'Add Posts' });
}
else return res.json(post);
}).catch (err => console.error(err))
});
Result of the route:
{
"postedby": [],
"Likes": 0,
"_id": "5fed8c12a4fb2c1e98ef09f6",
"Title": "New Age",
"Author": "Situma Prisco",
"ISBN": "23422",
"SelectedFile": "",
"Review": "",
"Date": "2020-12-31T08:30:10.321Z",
"__v": 0
},
I'm getting a blank Array on the populated user field(posteddby) .
Please help, What am I doing wrong? And yes, i do have a User Logged in
You are too close.
In your schema definition, postedby field itself is an array. Hence you can simply define it like :
postedby:[{
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
}]
Make sure that the ObjectID is stored properly in the postedby array.
Also, you are trying to find a single record based on the ID, hence you can use findById(req.params.id) or findOne({_id:req.params.id}) which would return a single document.

How to solve mongoose model statics error

I have the following model defined for my graphql API:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Post = Schema({
_id: Schema.Types.ObjectId,
title: { type: String, required: true },
description: { type: String, required: true },
content: { type: String, required: true },
comments: { type: [String], required: true },
tags: { type: [String], required: true },
stats: { type: [Number], required: true },
datePublished: { type: Date, required: true },
dateUpdated: { type: Date, required: true }
});
// TODO: Implement methods here
// Post.statics.getPost = function(args) {
// console.log(this.title);
// return this.model
// };
Post.statics.getPost = function(args) {
this.find({});
};
module.exports = mongoose.model("Post", Post, "posts");
I am willing to create a function in the model to fetch information from the database. But when I request the API for this function, I get the following response which is an error. I have also tried changing this to Post unsuccessfully.
{
"errors": [
{
"message": "this.find is not a function",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getPost"
]
}
],
"data": null
}
How can I solve this problem?
It does not look like you are instantiating an instance of mongoose schema. You need to use new. This will give you a reference to this.
const Post = new mongoose.Schema({ ...

get data into schema by id in mongoose

i have two schema i would like to get some info from another schema for example (firstName, lastName) from the userSchema by id that i would provide when adding new comment on the CommentsSchema
const CommentsSchema = new mongoose.Schema({
userId: {
type: String,
required: true
},
commentText: {
type: String,
required: true
},
time: {
type: Date,
default: Date.now
}
});
const UserSchema = new mongoose.Schema({
userName: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
}
});
You can use mongoose populate to get data from a referenced collection.
First you need to change comments schema to set up a reference to the User model.
You may need to change ref value, if you used a different user model name when you applied mongoose.model("User", UserSchema).
const CommentsSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
},
commentText: {
type: String,
required: true
},
time: {
type: Date,
default: Date.now
}
});
Let's say you have this user in users collection:
{
"_id": "5e312d5cab2e5028b8865be3",
"userName": "Mongoose",
"firstName": "Buk",
"lastName": "Lau",
"__v": 0
}
And this comment from this user:
{
"_id": "5e312d9cab2e5028b8865be4",
"userId": "5e312d5cab2e5028b8865be3",
"commentText": "this is a comment",
"time": "2020-01-29T07:00:44.126Z",
"__v": 0
}
Now you can access the user info from comment like this:
router.get("/comments/:id", async (req, res) => {
const result = await Comment.findById(req.params.id).populate("userId");
res.send(result);
});
The result will be like this:
{
"_id": "5e312d9cab2e5028b8865be4",
"userId": {
"_id": "5e312d5cab2e5028b8865be3",
"userName": "Mongoose",
"firstName": "Buk",
"lastName": "Lau",
"__v": 0
},
"commentText": "this is a comment",
"time": "2020-01-29T07:00:44.126Z",
"__v": 0
}

Resources