Thinky — Understanding Virtuals

Virtuals are additional fields for a given model. Their values can be set manually or automatically with defined functionality. A common virtual property is the full name of a person, composed of user’s first and last name.

Keep in mind: virtual properties don’t get persisted in the database. They only exist logically and are not written to the document’s table.

Thinky Series Overview

Thinky Model

We’ll use the user schema below for further examples. The user schema consists of two non-virtual properties: first and last and the virtual fullname property.

// define user schema
var User = thinky.createModel('user', {  
    first: String,
    last: String,
    fullname: {
        _type: 'virtual',
        default: function() {
            return this.first + " " + this.last;
        }
   }
});

// create a document
var mentalist = new User({  
    first: 'Patrick',
    last: 'Jane'
});

Assume we want to get the full name of mentalist, we can do this manually appending the first to last property:

console.log(mentalist.first + ' ' + mentalist.last); // Patrick Jane  

Additionally, we can directly use the fullname property. The defined default function already concatenates the first and last values. The provided default function for the virtual property is automatically executed during object creation. Therefore, fullname will return the desired value.

console.log(mentalist.fullname); // Patrick Jane  

Define a Virtual Property

The code snippet above illustrates how to define the virtual property and a default function returning the virtual’s value. However, we can define separate functions to get and set the virtual property value.

The required model attribute: { _type: "virtual }". This tells Thinky to handle fullname as virtual property.

var User = thinky.createModel('user', {  
    first: String,
    last: String,
    fullname: {
        _type: "virtual",
   }
});

Get Method

Actually, Thinky doesn’t split the getter and setter handling from normal model extension. We can use the known patterns and define additional model functions.

The virtuals get method is a function returning a the virtual value. You can do complex processing or just concatenate single document field values.

User.define('getFullname', function() {  
    return this.first + ' ' + this.last;
});

The code example above just concatenates the first and last property values.

console.log(mentalist.fullname); // Patrick Jane  

Set Method

Defining setter methods follows the same approach as getters: define a model function.

User.define('setFullname', function(name) {  
    var split = name.split(' ');

    this.fullname = name;
    this.first = split[0];
    this.last = split[1];
});

The first part of name is assigned to the first and the second part to the last property. This set method will override the previous model values and assign the ones we pass as name property.

var humor = new User({});

humor.setFullname('Kimball Cho');  
console.log(humor.first); // Kimball  
console.log(humor.last);  // Cho

humor.getFullname(); // Kimball Cho  

Regenerate Virtual Field Values

Thinky doesn’t recognize manually changed model values for virtual properties. The virtual field will still have the old value after changing any affected static property. You've to call generateVirtualValues() to regenerate them.

humor.getFullname(); // Kimball Cho  
humor.first = 'Wayne';  
humor.last = 'Rigsby';  
humor.getFullname(); // Kimball Cho

humor.generateVirtualValues();  
humor.getFullname(); // Wayne Rigsby  

Saving a document will do the job for you, automatically.

humor.getFullname(); // Kimball Cho  
humor.first = 'Wayne';  
humor.last = 'Rigsby';

humor.save().then(function() {  
    humor.getFullname(); // Wayne Rigsby
}).error(function(err) {
    console.log(err);
});

Queries and Field Selection

Virtuals are NOT available for document queries or field selection. Only non-virtual properties work for queries and field selections.

Conclusion

As you see, virtual properties aren’t static model properties. They’re additional model functions returning values based on the default schema fields.


Additional Resources

Explore the Library

Find interesting tutorials and solutions for your problems.