Lab / MongoDB

Как работают Virtuals в Mongoose

Virtuals это дополнительные поля для модели, что то вроде мутаторов в Laravel. Значение таких полей присваивается в специальной функции модели. Самый базовый пример такого поля можно описать следующим образом: у нас есть модель User с полями FirstName и SecondName, что бы не выводить в каждом шаблоне эти поля как 2 переменные мы можем создать Virtual с название FullName и склеить там два поля в одно:

userSchema.virtual('fullname').get(function() { 
 return this.first + ' ' + this.last;
});

Так же можно создаить и более сложные кейсы, например, у вас есть поле галлерея, но вы хотите использовать только первое изображение для обложки материала, при помощи виртуального поля (мутатора) мы можем слелать поле Cover которое будет содержать нужное нам изображение. Так же через подобное поле можно форматировать дату, делать тизер статьи и многое другое.

Обратите внимание — виртуальные свойства не сохраняются в базе данных. Они существуют только логически и не записываются в коллекцию документа.

Давайте создадим модель пользователя и на её примере рассмотри как устроены Virtuals в Express JS. Далее привожу код нашей модели:

var userSchema = new Schema({ 
 first: String,
 last: String
});

var User = mongoose.model('User', userSchema);

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

Без использования Virtuals для получения полного имени пользователя, нам бы понадобилось использовать вот такую конструкцию:

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

Давайте наконец приступим к созданию виртуального поля для автоматизации подобной рутины.

Mongoose обладает методами GET и SET для создания виртуальных полей. Метод GET отлично подходит для склеивания данных, например:

userSchema.virtual('fullname').get(function() { 
 return this.first + ' ' + this.last;
});

Соответственно теперь можно вызвать виртуальное поле:

console.log(mentalist.fullname); // Jhone Doe 

Метод SET в свою очередь можно использовать для извлечения данных из строки:

userSchema.virtual('fullname').set(function (name) { 
 var split = name.split(' '); // пробел служит разделителем
 this.first = split[0];
 this.last = split[1];
});

Виртуальные поля не доступны для построения запросов в Mongoose но вы можете обрабатывать полученную коллекцию на фронтенде или на бекенде после извлечения из базы.

Как видите, виртуальные свойства не являются свойствами статической модели. Это скорее дополнительный функционал модели, который возвращает виртуальные (мутированные) сущьности на основе значения полей модели или построенной вами кастомной логике.