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
});
Related
/I want to create a module section for a course website for which I will need a lesson schema as well so How can I design lesson schema , module schema , and course schema so they
work just how they are needed to workCurrently I am doing this/
import mongoose from 'mongoose'
const LessonSchema = new mongoose.Schema({
title: String,
content: String,
resource_url: String
})
const ModuleSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
lessons: [LessonSchema]
})
export const Module = mongoose.model('Module', ModuleSchema);
const CourseSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: 'Name is required'
},
price: {
type: String,
trim: true,
required: true
},
image: {
data: Buffer,
contentType: String
},
intro: {
type: String,
required :true
},
description: {
type: String,
trim: true
},
category: {
type: String,
required: 'Category is required'
},
updated: Date,
created: {
type: Date,
default: Date.now
},
instructor: {type: mongoose.Schema.ObjectId, ref: 'User'},
published: {
type: Boolean,
default: false
},
modules: [ModuleSchema]
})
export default mongoose.model('Course', CourseSchema)
Above was the schema and this is logic
const newLesson = async (req, res) => {
try {
let lesson = req.body.lesson
let course = await Course.find({modules: {_id: req.params.moduleId}})
console.log(course)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
const newModule = async (req, res) => {
try {
let lesson = req.body.lesson
let result = await Course.findByIdAndUpdate(req.course._id, {$push: {modules: {name: req.body.name, lessons: lesson}}, updated: Date.now()}, {new: true})
.populate('instructor', '_id name')
.exec()
res.json(result)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
**I have been brainstorming this from a while and cant get through it do you know how can I shape the schema and logic so that I can push lessons in module and then module in course schema ? **
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 }}
I have review and product model.If user give review on specific product(id) then it is stored in review model database but i donot like to store user review in product model database .so, i used virtual populate in product model instead of child referencing.After using virtual properties,if we use product id to see details,we can see review of user in json format but not saved in database.But the problem is my virtual properties (In Product Model) not working as it doesnt show review of user in json format when i send the request in that product id which already have review by user(stored in review model database).what is the problem here?
User Review on Product (id) stored in database
Sending Request of that product id to see review of user in json format using virtual properties(but no review found in json)
In Product Model
const productSchema = new Schema({
name: {
type: String,
required: true,
trim: true,
},
slug: {
type: String,
required: true,
unique: true,
},
price: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
trim: true,
},
offer: {
type: Number,
},
discount: {
type: Number,
},
productPictures: [{
img: {
type: String,
},
}, ],
mainCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub1Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
sub2Category: {
type: mongoose.Schema.Types.ObjectId,
ref: "category",
required: [true, "It is a required field"],
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "admin",
required: true,
},
vendor: {
type: mongoose.Schema.Types.ObjectId,
ref: "vendor",
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updatedAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
},
{
toJson: { virtuals: true },
toObject: { virtuals: true },
}
);
productSchema.virtual("reviews", {
ref: "review",
foreignField: "product",
localField: "_id",
// justOne: true
});
const Product = mongoose.model("product", productSchema);
module.exports = Product;
In Review Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const moment = require("moment");
const reviewSchema = new Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: [true, "Review must belong to user"],
},
product: {
type: mongoose.Schema.Types.ObjectId,
ref: "product",
required: [true, "Review must belong to the product"],
},
review: {
type: String,
required: [true, "Review cannot be empty"],
},
rating: {
type: Number,
min: 1,
max: 5,
},
createdAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
updateddAt: {
type: String,
default: moment().format("DD/MM/YYYY") + ";" + moment().format("hh:mm:ss"),
},
}, {
toJson: { virtuals: true },
toObject: { virtuals: true },
});
// pre middleware and populating user and product(we can also do populate in getAllReview in controller)
reviewSchema.pre(/^find/, function(next) {
// ^find here is we use regex and can able to find,findOne ...etc
this.populate({
path: "product",
select: " _id name",
}).populate({
path: "user",
select: " _id fullName",
});
next()
});
const Review = mongoose.model("review", reviewSchema);
module.exports = Review;
In Review.js
const Review = require("../../models/Review.Models")
exports.createReview = async(req, res) => {
const review = await Review.create(req.body)
return res.status(201).json({
status: true,
review
})
}
exports.getAllReviews = async(req, res) => {
try {
const reviews = await Review.find()
return res.status(200).json({
status: true,
totalReviews: reviews.length,
reviews
})
} catch (error) {
return res.status(400).json({
status: false,
error
})
}}
In Product.js
const Product = require("../../models/Product.Models");
exports.getProductDetailsById = async(req, res) => {
try {
const { productId } = req.params;
// const { productId } = req.body;
if (productId) {
const products = await Product.findOne({ _id: productId })
.populate('reviews')
return res.status(200).json({
status: true,
products,
});
} else {
console.log("error display");
return res.status(400).json({
status: false,
error: "params required...",
});
}
} catch (error) {
return res.status(400).json({
status: false,
error: error,
});
}
try this in Product.js
try {
if (productId) {
const products = await Product.findOne({ _id: productId }).populate(
"reviews"
);
console.log(products);
if (products) {
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
only need to add on response sending
return res.status(200).json({
status: true,
message: "Products is listed",
products,
reviw: products.reviews,
});
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'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();