I'm trying to populate my post's author fields (which is are object ids) with the corresponding author objects which are in a separate collection.
My controller code is as follows:
exports.readPosts = async (req, res) => {
try {
const posts = await Post.find({ board: req.params.board });
await posts.populate("author").execPopulate();
res.send(posts);
} catch (err) {
res.status(400).send(err.message);
}
};
I'm at a loss as to why this isn't working as I have very similar code in another controller method that is working just fine.
All help greatly appreciated.
Below is the relevant Model file:
const mongoose = require("mongoose");
const postSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true,
},
content: { type: String, required: true, trim: true },
comments: [
{
comment: {
type: String,
required: true,
trim: true,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
date: {
type: Date,
default: Date.now(),
},
},
],
author: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
board: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Board",
},
},
{ timestamps: true }
);
const Post = mongoose.model("Post", postSchema);
module.exports = Post;
posts is an array of models. populate must be called on a model. The preferred way to do this is at query time. It probably works on your other controller because you are using a findOne so it is returning the model, not the Array.
const posts = Post
.find({ board: req.params.board })
.populate('author')
.exec();
Related
I'm trying to delete a comment on a post, but I'm unable to find the comment. When I'm console.log(post.comments) it shows me all the comments but still, I can't find the comment. The error was Comment not found which I wrote to find that comment is still there or not. But the comment was there I matched the id with it. Help me I'm new to NodeJs. Help me to fix this
*As a frontend I'm using react and redux I think the problem is in the backend, I've also tested with the postman. Can't delete the comment from postman.
here is the comment route and controller
router.route('/:id/comment/:comment_id').delete(protect, deleteComment);
export const deleteComment = asyncHandler(async (req, res) => {
const post = await Post.findById(req.params.id);
const comment = post.comments.find(
(comment) => comment._id === req.params.comment_id
);
if (!comment) {
res.status(404);
throw new Error('Comment not found');
}
//Check User
if (comment.user.toString() === req.user._id.toString()) {
post.comments = post.comments.filter(
({ id }) => id !== req.params.comment_id
);
await post.save();
return res.json(post.comments);
} else {
res.status(401);
throw new Error('User not authorized');
}
});
here is the post model
import mongoose from 'mongoose';
const postSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: [true, 'Please Author is required'],
},
title: {
type: String,
required: true,
},
desc: {
type: String,
required: true,
},
img: {
type: String,
},
isLiked: {
type: Boolean,
default: false,
},
isDisLiked: {
type: Boolean,
default: false,
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
disLikes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
],
comments: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
text: {
type: String,
required: true,
},
name: {
type: String,
},
pic: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
},
],
categories: {
type: Array,
},
},
{
timestamps: { createdAt: 'created_at', updatedAt: 'modified_at' },
}
);
const Post = mongoose.model('Post', postSchema);
export default Post;
When you access to the _id you are accessing the instance of the ObjectId
You should try to compare with the id, that is a string representation of the _id
const comment = post.comments.find(
(comment) => comment.id === req.params.comment_id
);
I have 3 schemas including:
Building
const BuildingSchema = mongoose.Schema({
address: { type: String, required: true },
numberOfRooms: { type: Number, default: 0 },
});
Room
const RoomSchema = mongoose.Schema({
roomNumber: { type: Number, required: true, unique: false },
building: {
type: mongoose.Schema.Types.ObjectId,
ref: "Building",
required: true,
unique: false,
},
});
Agreement
const AgreementSchema = mongoose.Schema({
agreementNumber: { type: Number, unique: true },
room: {
type: mongoose.Schema.Types.ObjectId,
ref: "Room",
required: true,
unique: false,
},
});
My scenario is after deleting a building then
All rooms related to building
All agreements related to room
will be deleted too, currently I know how to delete rooms related to building:
BuildingSchema.pre("deleteOne", function (next) {
Room.deleteMany({ building: this._conditions._id }).exec();
next();
});
So how I can do it using pre middleware ?
My mongoose version: ^6.0.12
Thank you!
BuildingSchema.pre("remove", function (next) {
Room.deleteMany({ building: this._conditions._id }).exec();
next();
});
remember remove the building using building.remove() mongoose base function :)
This is my solution.
BuildingSchema.pre("deleteOne", async function (next) {
const buildingId = this._conditions._id;
await Room.find({ building: buildingId }, (err, rooms) => {
rooms.map(async (item) => {
await Agreement.deleteMany({ room: item._id }); // => Delete all Agreements related to Room
});
}).clone();
await Room.deleteMany({ building: buildingId }); // => Delete all Rooms related to Building
});
A team has many projects. Im trying to delete a project, and so I need to delete it in marcsEquipa[] too.
TEAM SCHEMA
const EquipaSchema = new mongoose.Schema({
trab1: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Trab'
},
trab2: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Trab'
},
trab3: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Trab'
},
teamName: {
type: String,
required: true
},
marcsEquipa: [{
type: Schema.Types.ObjectId,
ref: 'Marcacao'
}]
},
{collection: 'Equipas'})
Function Delete Project
exports.deleteMarc = async (req,res) => {
console.log("Deleting Project..");
console.log(req.params._id);
console.log(req.params.equipa);
try{
console.log("1");
const equipa = await
Equipas.updateOne({ _id: req.params.equipa}, { $pull: { marcsEquipa: { _id: req.params._id}}}, { multi: true });
equipa.save();
console.log("1");
//await Marcacao.deleteOne({_id: req.params._id});
res.status(200).json();
console.log("1");
}catch(err) {
res.status(400).json({message: err});
}
}
I've tried this and it manages to delete the Project but it doesn't delete it within the array of Projects in Team. Can anyone help?
You are trying to pull the item with _id property, but the items are just the string representation of ObjectId. So, instead of this:
{ $pull: { marcsEquipa: { _id: req.params._id }}}
do this:
{ $pull: { marcsEquipa: req.params._id }}
There are my schemas
//ProjectModel
const ProjectSchema: Schema = new Schema(
owner: { type: Schema.Types.ObjectId, ref: "User" },
users: [{type: Schema.Types.ObjectId, ref: "ProjectUser", unique: true }]
);
//Project User model
const ProjectUserSchema = new Schema(
{
user: { type: Schema.Types.ObjectId, ref: "User", require: true },
role: {
type: String,
default: 'basic',
enum: ["basic", "projectuser", "moderator", "admin"]
},
project: { type: Schema.Types.ObjectId, ref: "Project", require: true },
},
{
timestamps: true,
usePushEach: true,
}
);
The User model has common fields like password, name, etc.
I want to find User of a ProjectModel either among the owner (UserSchema) or among users (ProjectUserSchema)
ProjectModel.findOne()
.or([{ owner: req.params.user }, { "users.user": req.params.user }])
.then(project => {
res.json(project);
});
But it returns null. And condition .or([{ owner: req.params.user }, { "users._id": "PROJECT USER ID" }]) doesn't work either.
What should I do?
You need to convert the incoming req.params.user from string to ObjectId. Try this:
const mongoose = require('mongoose');
const getProjectByUser = (req, res) => {
let userId = mongoose.Types.ObjectId(req.params.user);
ProjectModel
.findOne({
$or: [
{ "owner": userId },
{ "users": userId }
]
})
.then(project => {
res.json(project);
})
.catch(e => {
res.json({ error: "Error!" });
});
}
I have a users model which includes a locationsSchema in it:
const locationSchema = require('./location.js');
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
token: {
type: String,
require: true,
},
locations: [locationSchema],
passwordDigest: String,
}, {
timestamps: true,
});
My locations model is :
const mongoose = require('mongoose');
const locationSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
city: {
type: String,
},
region: {
type: String,
},
country: {
type: String,
},
coords: {
lat: {
type: Number,
require: true
},
long: {
type: Number,
require: true
},
},
visited: {
type: Boolean,
require: true,
default: false,
},
comment: {
type: String,
},
}, {
timestamps: true,
});
and finally the create action in my controller for locations is:
const controller = require('lib/wiring/controller');
const models = require('app/models');
const User = models.user;
const Location = models.location;
const create = (req, res, next) => {
User.findById(req.body.user.id).then (function(user){
let location = Object.assign(req.body.location);
user.locations.push(location);
return user.save();
})
.then(user => res.json({ user }))
.catch(err => next(err));
};
When I try to send a curl POST request to locations I get:
{"error":{"message":"this._schema.caster.cast is not a function","error":{}}}
console.logging user, user.locations, and locations just before the
user.locations.push(location);
line returns exactly what I'd expect. I'm fairly certain the error is stemming from the push function call. Any insight would be much appreciated.
your embedding location model
const locationSchema = require('./location.js');
so only you getting this error,
model can't be embedding schema only embedding
const locationSchema = require('./location.js'). schema;
so you try this