Mongoose virtual properties: computed fields that don't persist
Mongoose virtual properties compute read-only fields on-the-fly keep MongoDB documents lean and appear in JSON API responses when the toJSON option is enabled. This guide covers definition version notes and verification.
08 Jul 2026, 13:35 UTC

Problem
\nAPI responses often need fields that combine or transform existing document data such as a full name from first and last or a tax-included price. Adding these as stored fields inflates the MongoDB document and creates duplication risk. Mongoose virtual properties compute values at read time keeping the database schema clean while still delivering computed data to clients.
\nTakeaway
\nVirtual properties let you define computed read-only fields that auto-update with document changes never persist to MongoDB and appear in JSON output when the toJSON option is enabled a practical alternative to calculated stored fields.
\nPrerequisites
\n- \n
- Node.js v14 or later recommended \n
- Mongoose v5.10+ v6.x or v7.x behavior is consistent for basic virtuals but getter signatures and middleware interaction may vary per major version \n
- A running MongoDB instance and a connection string \n
Procedure
\n- \n
- Define the virtual on your schema specifying a getter that receives the document instance: \n
- Enable virtual inclusion in JSON serialization: \n
- Create a document and inspect the serialized output: \n
schema.virtual('fullName').get(function(){return this.first+this.last})\nschema.set('toJSON', { virtuals: true })\nconst doc = new Model({ first: 'Ada', last: 'Lovelace' }); console.log(doc.toJSON())\nExpected checks
\n- \n
- Run console.log(doc.toJSON()) and confirm fullName appears only when { virtuals: true } is set by default it is omitted. \n
- Check the Mongoose version with console.log(mongoose.version) and compare against release notes for any breaking changes between 5.x 6.x and 7.x. \n
- Query a document from the database and verify that fullName does not appear in the raw MongoDB document confirming it is not persisted. \n
Limitations
\n- \n
- A virtuals value is computed on every read. Attempting to save a document with a virtual set via a setter will not write the value to MongoDB unless the setter explicitly assigns to a real schema path. \n
- Without { virtuals: true } in the toJSON option virtuals are excluded from doc.toJSON() and res.json() outputs which can silently break API fields. \n
- If you define a setter as the second argument to schema.virtual(path getter setter) it must explicitly write to a real path otherwise the assignment is lost after the document leaves the Mongoose layer. \n
Practical verification
\n- \n
- In a Node REPL or test file create the schema with a virtual instantiate a document and run console.log(doc.toJSON()) to confirm the virtual appears when the option is set. \n
- Check mongoose.version and consult the official Mongoose release notes for any version-specific notes on virtual getter signatures or middleware interaction. \n
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.