10

Short and clear: is there any way to prevent setting a schema field but allowing to get the value?

I've been around the Mongoose Documentation but can't find what I'm looking for.

jviotti
  • 17,881
  • 26
  • 89
  • 148

4 Answers4

16

An alternative if you want to set a default value that can never be changed:

var schema = new Schema({
  securedField: {
    type: String,
    default: 'Forever',
    set: function (val) { return this.securedField; }
});
Jason Cust
  • 10,743
  • 2
  • 33
  • 45
  • Does not appear to work anymore in Mongoose 5.0.15 Value was correctly set to "securedField": "Forever" but FindByIdandUpdate(...) changes it. – jfrobishow May 17 '18 at 01:03
  • 2
    @jfrobishow That's due to a change in Mongoose 5 where `this` in setters for a query (`findByIdAndUpdate` in your case) refers to the query and not the document. See the last bit in the documentation for [`set`](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set). – Jason Cust May 17 '18 at 13:43
4

Define the field as a virtual getter instead of a traditional field.

For example, say you wanted to make the pop field of your collection read-only when accessed via Mongoose:

var schema = new Schema({
    city: String,
    state: String
});

schema.virtual('pop').get(function() {
    return this._doc.pop;
});

By accessing the private _doc member of your model instance it's possible this may break in the future, but this worked fine when I tested it just now.

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
  • how does this work? virtuals don't get persisted, right? – sidgate Sep 01 '16 at 23:25
  • 1
    @sidgate This is an old answer and a bit of a hack to expose a field not defined in the schema, but present in the underlying documents. So you're right that virtuals don't get persisted, but since the `pop` field is already there it works because the raw document is available via the (undocumented) `_doc` field. – JohnnyHK Sep 02 '16 at 01:56
2

Since mongoose 5.6 you can do: immutable: true

var schema = new Schema({
  securedField: {
    type: String,
    default: 'Forever',
    immutable: true
  }
});
Vasyl Boroviak
  • 5,959
  • 5
  • 51
  • 70
0

You can just return from set the same value as the default value, no need to reference the _this document:

var schema = new Schema({
  securedField: {
    type: String,
    default: 'Forever',
    set: () => 'Forever'
});
Paweł Otto
  • 136
  • 2
  • 6