I am getting this error: Cannot read property 'likes' of null - node.js

I am getting error on console that : Cannot read property 'likes' of null
I am using postman for getting requests and putting response and response.
The array 'likes' is empty and here I am trying to insert the user id inside it but unable to insert it through unshift() method.
This is schema defined in a file Posts.js
const { text } = require('express');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
avatar: {
type: String
},
likes: [
{
users: {
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
comment: [
{
users: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String,
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Post = mongoose.model('post', PostSchema);
This is a express code for put request in file posts.js
const express = require('express');
const router = express.Router();
const { check, validationResult } = require('express-validator/check');
const auth = require('../../middleware/auth');
const Posts = require('../../models/Posts');
const User = require('../../models/User');
const { route } = require('./profile');
router.put('/like/:id', auth, async(req, res) => {
try {
const post = await Post.findById(req.params.id);
// Check if the post has already been liked
if(post.likes.filter(like => like.user.toString() === req.user.id).length > 0) {
return res.status(400).json({ msg: 'Post already liked' });
}
post.likes.unshift({ user: req.user.id });
await post.save();
res.json(post.likes);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});

Here is the typo error I made. In the schema Posts.js in likes and comment array I wrote users instead of user.
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
avatar: {
type: String
},
likes: [
{
users: { // Here it has to be user
type: Schema.Types.ObjectId,
ref: 'users'
}
}
],
comment: [
{
users: { //Here it has to be user
type: Schema.Types.ObjectId,
ref: 'users'
},

Related

Mongoose - Selecting and Sending Virtuals from Populated Fields

I am having a little trouble getting my mongoose virtuals to show up from deep populated fields. Here is the code of the backend function that is not behaving as I'd like it to:
exports.get_user_feed = async (req, res, next) => {
const options = { sort: { date: -1 } };
const user = await User.find(
{ username: req.params.user },
"username posts avatar followers following"
)
.populate({
path: "posts",
options,
populate: [
{
path: "author",
},
{ path: "comments", populate: { path: "author" } },
],
})
.sort({ "posts.date": 1 });
res.json({ ...user });
};
And here is the comment schema:
const mongoose = require("mongoose");
const { DateTime } = require("luxon");
const Schema = mongoose.Schema;
const CommentSchema = new Schema({
targetPost: { type: Schema.Types.ObjectId, ref: "Post", required: true },
author: { type: Schema.Types.ObjectId, ref: "User", required: true },
date: { type: Date, required: true },
content: { type: String, maxlength: 400 },
comments: [{ type: Schema.Types.ObjectId, ref: "Comment" }],
stars: [{ type: Schema.Types.ObjectId, ref: "User" }],
});
// Virtual for post's URL
CommentSchema.virtual("url").get(function () {
return "/" + this.targetPost.url + this._id;
});
// Virtual for formatted date.
CommentSchema.virtual("formatted_date").get(function () {
return (
DateTime.fromJSDate(this.date).toLocaleString(DateTime.DATE_MED) +
" at " +
DateTime.fromJSDate(this.date).toLocaleString(DateTime.TIME_SIMPLE)
);
});
//Export model
module.exports = mongoose.model("Comment", CommentSchema);
My goal is to get the comments from each post to also include the formatted_date of the comment, but this virtual is not getting included in the response that is sent - all the regular properties are being sent but not the virtual. Any help here would be appreciated.
Add this code in your Commnet Schema file before module.exports.
CommentSchema.method('toJSON', function () {
const {
...object
} = this.toObject({ virtuals:true });
return object;
});

Router.post an array of Object ID'S using Mongoose and NodeJs router.post

I almost have the desired functionality but it's not exactly what I wanted to approach.
I have two model schema, Control and SubControl. The SubControl is referenced in the Control model. I want to post the control model + a reference of the SubControl.
My post method:
router.post(
'/add',
auth,
role.checkRole(role.ROLES.Admin, role.ROLES.Regulator),
async (req, res) => {
try {
const subControl = new SubControl({...req.body});
const subControlDoc = await subControl.save();
const control = new Control({...req.body});
control.subControl.push(subControlDoc._id);
const savedControl = await control.save();
res.status(200).json({
success: true,
message: `Control has been added successfully!`,
control: savedControl
});
} catch (error) {
return res.status(400).json({
error
// error: 'Your request could not be processed. Please try again.'
});
}
}
);
My Control Schema:
const ControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
mainControl: {
type: String
},
subControl: [{
subControlNo: {type: Mongoose.Schema.Types.String, ref: 'SubControl'}
}],
controlDescription: {
type: String,
trim: true
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('Control', ControlSchema);
My SubControl schema:
const SubControlSchema = new Schema({
_id: {
type: Schema.ObjectId,
auto: true
},
subControlNo: {
type: String
},
updated: Date,
created: {
type: Date,
default: Date.now
}
});
module.exports = Mongoose.model('SubControl', SubControlSchema);
Postman:
{
"mainControl": "nn",
"controlDescription": "controldescription",
"subControl":
[
{
"subControlNo": "1-2"
},
{
"subControlNo": "1-2-1"
}
]
}
Result I'm getting:
Question: Why am I getting 3 object id's although I inserted 2 and why only the last object ID is saved in my SubControl database? I this the way to add array of object id's or not?

500 Error when using method populate in Express and Mongo

I cannot fetch users data from Mongo when I use populate() method for posts of users.
router.get("/users", (req, res) => {
User.find()
.populate("posts")
.exec()
.then((users) => {
res.json({ users });
})
.catch((err) => console.log(err));
});
Mongo Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const { ObjectId } = mongoose.Schema.Types;
const Post = require("../models/Post");
const UserSchema = new Schema({
name: {
type: String,
required: true
},
username: {
type: String,
requied: true
},
userimg: {
type: String
},
followers: [
{
type: ObjectId,
ref: "User"
}
],
following: [
{
type: ObjectId,
ref: "User"
}
],
posts: [
{
type: ObjectId,
ref: "Post"
}
],
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model("users", UserSchema);
When I remove .populate("posts") than I get 200 Success status and users data but without popoulation of referred posts from the posts collection.
So i'll be doing a little modification to your model file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Post = require("../models/Post");
const UserSchema = new Schema({
name: {
type: String,
required: true
},
username: {
type: String,
requied: true
},
userimg: {
type: String
},
followers: [
{
type: Schema.Types.ObjectId,
ref: "User"
}
],
following: [
{
type: Schema.Types.ObjectId,
ref: "User"
}
],
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post"
}
],
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model("User", UserSchema);
Can you change your exec() to execPopulate()
router.get("/users", (req, res) => {
User.find()
.populate("posts")
.execPopulate()
.then((users) => {
res.json({ users });
})
.catch((err) => console.log(err));
});
Thank you all for your help. I found the error:
ref: "posts" instead of ref: "Post"
ref: "users" instead of ref: "User"

When i fetch comments for particular Playlist i am getting all comments. And How can i get the other properties of comments?

This is My Playlist Schema:
when i fetch the comments for particular playlist i got only ids for the comments. How can i send all detail of comments of particular playlist to the front end?
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// const Video = require('./Video');
const User = require('./User');
const Comment = require('./Comment');
const VideoSchema = new Schema(
{
url: {
type: String
// required: true
},
shortDescription: {
type: String,
max: 120
// required: true
},
description: {
type: String,
min: 20,
max: 200
},
// createdOn: {
// type: Date,
// default: Date.now
// },
createdBy: { type: Schema.Types.ObjectId, ref: 'User' },
uploadedBy: { type: Schema.Types.ObjectId, ref: 'User' }
// uploadedOn: {
// type: Date,
// default: Date.now
// }
},
{
timestamps: true
}
);
const PlaylistSchema = new Schema(
{
name: {
type: String,
required: true
},
detail: {
type: String,
max: 100
},
tag: [ { type: String } ],
// user: {
// type: mongoose.Schema.Types.ObjectId,
// ref: 'User'
// },
uploadBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
videos: [ VideoSchema ],
// videos: [ { type: String } ],
// createdOn: { type: Date, default: Date.now },
updateBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
// updateOn: { type: Date, default: Date.now },
comments: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Comment' } ]
},
{
timestamps: true
}
);
module.exports = Playlist = mongoose.model('Playlist', PlaylistSchema);
This is my Comment Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const User = require('./User');
const CommentSchema = new Schema(
{
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
detail: {
type: String,
max: 200
},
// createdOn: {
// type: Date,
// default: Date.now
// },
// updatedOn: {
// type: Date,
// default: Date.now
// },
updatedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
},
{
timestamps: true
}
);
CommentSchema.pre('remove', async function(next) {
try {
let foundUser = await User.findById(this.createdBy);
foundUser.comments.remove(this.id);
await User.save();
return next();
} catch (error) {
return next(error);
}
});
module.exports = Comment = mongoose.model('Comment', CommentSchema);
This is the function which will run when i fetch for comments
exports.getComments = async function(req, res, next) {
try {
console.log('request came for fetching comment');
let foundPlaylist = await Playlist.findById(req.params.playlist_id).populate('comments');
console.log('foundPlaylist:', foundPlaylist);
let foundComments = foundPlaylist.comments.map(async (comment) => {
return await Comment.findById(comment._id).populate('createdBy', { firstName: true });
});
return res.status(200).json(comments);
} catch (error) {
return next(error);
}
};
when i fetch the comments for particular playlist i got only ids for
the comments. How can i send all detail of comments of particular
playlist to the front end?
//Routes
router.route('/').get(getComments);
//index route
app.use('/api/users/:id/playlists/:playlist_id/comments', loginRequired, ensureCorrectUser, commentAuthRoute);
The comments field was defined to only contain a dbref:
comments: [ { type: mongoose.Schema.Types.ObjectId, ref: 'Comment' } ]
To retrieve the matching comment documents, use populate

How to make a comment on board in Nodejs

I am creating an application using Nodejs and React, but the comment function does not work. I do not know the cause.
Error :
board validation failed: comments.0.content: Path content is required.
I don't know why this is not working. What mistake did I make?
route/api/board.js
router.post(
'/:id/comments',
[
auth,
[
check('content', 'input your content. ')
.not()
.isEmpty()
]
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() }, 'isEmpty');
}
try {
const user = await User.findById(req.user.id).select('-password');
const board = await Board.findById(req.params.id);
const newComment = new Board({
content: req.body.content,
user: req.user.id
});
board.comments.unshift(newComment);
await board.save();
res.json(board.comments);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error!!');
}
}
);
models/Board.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const BoardSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
view_count: {
type: Number,
default: 1
},
created_at: {
type: Date,
default: Date.now
},
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user'
}
}
],
comments: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'user'
},
content: {
type: String,
required: true
},
created_at: {
type: Date,
default: Date.now
}
}
]
});
module.exports = Board = mongoose.model('board', BoardSchema);
The error is pretty explicit, one of your comments in the comments array doesn't have a property content which seem to be required based on your model.
So double check what you are sending to the server by debugging/logging the content of the req.body.

Resources