So I'm building a backend with NestJs and Typegoose, having the following models:
DEPARTMENT
@modelOptions({ schemaOptions: { collection: 'user_department', toJSON: { virtuals: true }, toObject: { virtuals: true }, id: false } })
export class Department {
@prop({ required: true })
_id: mongoose.Types.ObjectId;
@prop({ required: true })
name: string;
@prop({ ref: () => User, type: String })
public supervisors: Ref<User>[];
members: User[];
static paginate: PaginateMethod<Department>;
}
USER
@modelOptions({ schemaOptions: { collection: 'user' } })
export class User {
@prop({ required: true, type: String })
_id: string;
@prop({ required: true })
userName: string;
@prop({ required: true })
firstName: string;
@prop({ required: true })
lastName: string;
[...]
@prop({ ref: () => Department, default: [] })
memberOfDepartments?: Ref<Department>[];
static paginate: PaginateMethod<User>;
}
As you might guess, one user might be in many departments and one department can have many members(users). As the count of departments is more or less limited (compared with users), I decided to use one way embedding like described here: Two Way Embedding vs. One Way Embedding in MongoDB (Many-To-Many). That's the reason User holds the array "memberOfDepartments", but Department does not save a Member-array (as the @prop is missing).
The first question is, when I request the Department-object, how can I query members of it? The query must look for users where the department._id is in the array memberOfDepartments.
I tried multiple stuff here, like virtual populate: https://typegoose.github.io/typegoose/docs/api/virtuals/#virtual-populate like this on department.model:
@prop({
ref: () => User,
foreignField: 'memberOfDepartments',
localField: '_id', // compare this to the foreign document's value defined in "foreignField"
justOne: false
})
public members: Ref<User>[];
But it won't output that property. My guess is, that this only works for one-to-many on the one site... I also tried with set/get but I have trouble using the UserModel inside DepartmentModel.
Currently I'm "cheating" by doing this in the service:
async findDepartmentById(id: string): Promise<Department> {
const res = await this.departmentModel
.findById(id)
.populate({ path: 'supervisors', model: User })
.lean()
.exec();
res.members = await this.userModel.find({ memberOfDepartments: res._id })
.lean()
.exec()
if (!res) {
throw new HttpException(
'No Department with the id=' + id + ' found.',
HttpStatus.NOT_FOUND,
);
}
return res;
}
.. but I think this is not the proper solution to this, as my guess is it belongs in the model.
The second question is, how would I handle a delete of a department resulting in that i have to delete the references to that dep. in the user?
I know that there is documentation for mongodb and mongoose out there, but I just could not get my head arround how this would be done "the typegoose way", since the typegoose docs seem very limited to me. Any hints appreciated.