Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a Mongoose schema field read-only

I have a Mongoose "User" schema, and one of the fields needs to be read-only. (the "accounts" field can be updated externally, so I don't want updates to the User to overwrite the changes.)

var UserSchema = new Schema({
firstName: {
    type: String,
    trim: true,
    default: '',
    validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
    type: String,
    trim: true,
    default: '',
    validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
    type: String,
    trim: true
},
email: {
    type: String,
    trim: true,
    default: '',
    validate: [validateLocalStrategyProperty, 'Please fill in your email'],
    match: [/.+\@.+\..+/, 'Please fill a valid email address']
},
username: {
    type: String,
    unique: 'Username already exists',
    required: 'Please fill in a username',
    trim: true
},
password: {
    type: String,
},
accounts: [{
        account_hash: {type: String},
        account_name: {type: String}        
    }],

updated: {
    type: Date
},
created: {
    type: Date,
    default: Date.now
}
}

I've seen answers recommending making the field virtual, but on save, the field gets removed from Mongo. Is there an easy way to make specific fields in a Mongoose schema read-only?

like image 532
DShultz Avatar asked Dec 07 '22 13:12

DShultz


2 Answers

With the latest version of Mongoose, you can set 'immutable' as a property on the the field that you want to be immutable. You can read more here Mongoose immutable.

So you can do something like

const schema = new Schema({
  name: { type: String, immutable: true },
  age: Number
});

const Model = mongoose.model('Test', schema);

await Model.create({ name: 'test' });
const doc = await Model.findOne();

doc.isNew; // false
doc.name = 'new name';
doc.name; // 'test', because `name` is immutable

The downside to this is that your users will not get an error message that lets them know that the field they're trying to update or have updated is read only

like image 99
Emmanuel Jucaban Avatar answered Dec 11 '22 09:12

Emmanuel Jucaban


It seems to me your best bet is the pre middleware for save/update.

You can check if the fields you do not want changed are being changed with isModified and simply throw error about your fields being read only from there:

someSchema.pre('save', function(next) { 
  if(this.isModified('someField')) {
    throw 'someField is read only!'
  }
  else {
    next();
  }
});

For update you should be getting the updates via this.getUpdate() and look in there for your fields.

like image 26
Akrion Avatar answered Dec 11 '22 08:12

Akrion