Virtuals in mongoose

oviecodes

Godwin Alexander

Posted on September 8, 2020

Virtuals in mongoose

What are Virtuals?

We may wish to have certain properties that we can call on our documents but don't want to save those properties in the database.
Examples of such properties are properties that

  • get the full name of a user,
  • get the number of a comments from the comments array of a user.

These properties are usually not required when the document is created, but occur as a result of some sort of processing carried out on the document.
As stated in the mongoose documentation, Virtuals are document properties that you can get and set but that do not get persisted to MongoDB.
Let's get to creating some virtuals of our own, Its an easy process in mongoose.
Suppose we have the following user model,

const userSchema = new mongoose.Schema({
    firstname: {
        type: String,
        required: true
    },
    lastname: {
        type: String
    }
})

const User = mongoose.model('user', userSchema)
Enter fullscreen mode Exit fullscreen mode

and we want access to a user's full name (i.e firstname + lastname). We might do something like

const user = await User.create({
     firstname: 'Godwin',
     lastname: 'Alexander'
})

console.log(`${user.firstname} ${user.lastname}`) 
Enter fullscreen mode Exit fullscreen mode

This would suffice for an operation that's as simple as getting the full name of a user, imagine if we had to carry out more sophisticated processing on the data model that requires 10+ lines of code in realtime. Having to write those 10+ lines of code over and over again becomes boring and cumbersome, thankfully there's a way out. All you have to do is declare a virtual in the data model as follows

userSchema.virtual('fullname')
.get(function() {
    return `${this.firstname} ${this.lastname}`
})
Enter fullscreen mode Exit fullscreen mode

This logic creates a virtual field on the schema called fullname which returns a string containing the firstname and lastname.
The fullname virtual is not stored in Mongodb, rather it is created during runtime and is attached to model.

const user = await User.create({
        firstname: 'money',
        lastname: 'man'
    })
console.log(`Welcome ${user.fullname}`) // money man
Enter fullscreen mode Exit fullscreen mode

As we can see from the above logic, virtuals also help with abstraction.

Warning: Since virtuals aren't stored in mongodb, you can't query with them. Doing something like this will fail

const users = await User.findOne({ fullname: 'Godwin Alexander' })
Enter fullscreen mode Exit fullscreen mode

Apart from the get method on virtuals, a set method is also available. Setters are useful for de-composing a single value into multiple values for storage.
Suppose we update our userSchema to look like the following code

const userSchema = new mongoose.Schema({
    firstname: {
        type: String,
        required: true
    },
    lastname: {
        type: String
    },
    initials: {
        type: String
    }
})
Enter fullscreen mode Exit fullscreen mode

Where initials is simply a string made up of the first letter of a user's first name and the first letter of the last name. We don't want to ask user to provide their initials, of course not. Mongoose provides a way to set such values, as long as they are specified in the schema.

userSchema.virtual('setInitials')
    .set(function(name) {
        const [first, last] = name.split(' ')
        this.initials = `${first[0]}${last[0]}`.toUpperCase()
    })
Enter fullscreen mode Exit fullscreen mode

Now, we can do this

const user = await User.create({
        firstname: 'mayweather',
        lastname: 'floyd'
    })

user.setInitials = user.fullname
console.log(user.initials) //MF
Enter fullscreen mode Exit fullscreen mode

That's all for this tutorial, the mongoose documentation however could give you more insight into virtuals and other amazing things which could be done with mongoose and Mongodb. See you in the next article.

πŸ’– πŸ’ͺ πŸ™… 🚩
oviecodes
Godwin Alexander

Posted on September 8, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related