I need a hint in working with mongoose and using type schema. All I want to do is to create users and users can have roles.
I have user model like this:
const userSchema = mongoose.Schema(
{
_id: {
type: String,
default: randomUUID
},
email: {
type: String,
unique: true,
required: [true, 'email is required']
},
password: {
type: String,
required: [true, 'password is required']
},
roles: {
type: [roleModel.schema]
}
},
{
timestamps: true
}
)
What I wanted to do, was to tell the user model, that roles is an array of roles, and these roles should follow roleModelSchema:
const roleSchema = mongoose.Schema(
{
_id: {
type: String,
default: randomUUID
},
name: {
type: String,
unique: true,
required: [true, 'Name is required']
},
permissions: {
type: [String],
}
},
{
timestamps: true
}
)
But this aproach actualy not working as I expected. For example I created a new user with role named 'Test1', it works great. But When I try to add another user with role 'Test1' mongoose throw an error on name duplicity.
{
"message": "E11000 duplicate key error collection: test.users index: roles.name_1 dup key: { roles.name: \"Test1\" }"
}
So as I see ii - atribute roles with type schema on users actualy does not reffer to original schema documents, but creating a new set of 'subDocuments', which follows the rules like uniqe name etc.
So what is the right aproach in Mongoose to define that user has roles and the roles are actualy other documents?
The way you've defined it, Mongoose treats roles as an embedded sub-document array rather than a reference to documents in the roles collection.
You need to define a reference to the roles collection in your user schema. You can achieve this using Mongoose's population feature.
const userSchema = mongoose.Schema({
_id: {
type: String,
default: randomUUID
},
email: {
type: String,
unique: true,
required: [true, 'email is required']
},
password: {
type: String,
required: [true, 'password is required']
},
roles: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Role'
}]
}, {
timestamps: true
});
roles will now store an array of ObjectIds referencing documents in the roles collection. When you retrieve a user document, you can use Mongoose's populate() method to automatically replace these ObjectIds with the actual role documents. Here is what I mean:
User.findOne({ /* your query */ })
.populate('roles')
... /* Continue accordingly */
Hopefully I was able to help, wish you the best of luck! :)