Spec-Zone.ru › Mongoose

Виртуальные свойства Mongoose

В Mongoose виртуальное свойство — это свойство, которое не хранится в MongoDB. Виртуальные свойства обычно используются для вычисленных свойств документов.

  • Ваше первое виртуальное свойство
  • Виртуальные установщики
  • Виртуальные свойства в JSON
  • Виртуальные свойства с Lean
  • Ограничения
  • Загрузка
  • Виртуальные свойства через параметры схемы
  • Дополнительные материалы

Ваше первое виртуальное свойство

Предположим, у вас есть модель User. Каждый пользователь имеет email, но вы также хотите получить домен электронной почты. Например, доменная часть 'test@gmail.com' — это 'gmail.com'.

Ниже приведен один способ реализации свойства domain с помощью виртуального свойства. Вы определяете виртуальные свойства в схеме, используя функцию Schema#virtual().

const userSchema = mongoose.Schema({
  email: String
});
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
  return this.email.slice(this.email.indexOf('@') + 1);
});
const User = mongoose.model('User', userSchema);

const doc = await User.create({ email: 'test@gmail.com' });
// `domain` is now a property on User documents.
doc.domain; // 'gmail.com'

Функция Schema#virtual() возвращает объект VirtualType. В отличие от обычных свойств документа, виртуальные свойства не имеют никакого базового значения, и Mongoose не выполняет никакой принудительной типизации для виртуальных свойств. Однако виртуальные свойства имеют геттеры и сеттеры, что делает их идеальными для вычисленных свойств, как в примере domain выше.

Виртуальные установщики

Вы также можете использовать виртуальные свойства для одновременной установки нескольких свойств в качестве альтернативы пользовательским установщикам для обычных свойств. Например, предположим, у вас есть два строковых свойства: firstName и lastName. Вы можете создать виртуальное свойство fullName, которое позволит установить оба этих свойства одновременно. Важный момент заключается в том, что в геттерах и сеттерах виртуальных свойств this ссылается на документ, к которому привязано виртуальное свойство.

const userSchema = mongoose.Schema({
  firstName: String,
  lastName: String
});
// Create a virtual property `fullName` with a getter and setter.
userSchema.virtual('fullName').
  get(function() { return `${this.firstName} ${this.lastName}`; }).
  set(function(v) {
    // `v` is the value being set, so use the value to set
    // `firstName` and `lastName`.
    const firstName = v.substring(0, v.indexOf(' '));
    const lastName = v.substring(v.indexOf(' ') + 1);
    this.set({ firstName, lastName });
  });
const User = mongoose.model('User', userSchema);

const doc = new User();
// Vanilla JavaScript assignment triggers the setter
doc.fullName = 'Jean-Luc Picard';

doc.fullName; // 'Jean-Luc Picard'
doc.firstName; // 'Jean-Luc'
doc.lastName; // 'Picard'

Виртуальные свойства в JSON

По умолчанию Mongoose не включает виртуальные свойства при преобразовании документа в JSON. Например, если вы передадите документ в функцию Express res.json(), виртуальные свойства по умолчанию не будут включены.

Чтобы включить виртуальные свойства в res.json(), вам нужно установить параметр схемы toJSON в значение { virtuals: true }.

const opts = { toJSON: { virtuals: true } };
const userSchema = mongoose.Schema({
  _id: Number,
  email: String
}, opts);
// Create a virtual property `domain` that's computed from `email`.
userSchema.virtual('domain').get(function() {
  return this.email.slice(this.email.indexOf('@') + 1);
});
const User = mongoose.model('User', userSchema);

const doc = new User({ _id: 1, email: 'test@gmail.com' });

doc.toJSON().domain; // 'gmail.com'
// {"_id":1,"email":"test@gmail.com","domain":"gmail.com","id":"1"}
JSON.stringify(doc);

// To skip applying virtuals, pass `virtuals: false` to `toJSON()`
doc.toJSON({ virtuals: false }).domain; // undefined

Виртуальные свойства в console.log()

По умолчанию Mongoose не включает виртуальные свойства в вывод console.log(). Чтобы включить виртуальные свойства в console.log(), вам нужно установить параметр схемы toObject в значение { virtuals: true }, или использовать toObject() перед выводом объекта.

console.log(doc.toObject({ virtuals: true }));

Виртуальные свойства с Lean

Виртуальные свойства — это свойства документов Mongoose. Если вы используете параметр lean, это означает, что ваши запросы возвращают объекты POJO вместо полных документов Mongoose. Это означает, что виртуальные свойства не будут включены, если вы используете lean().

const fullDoc = await User.findOne();
fullDoc.domain; // 'gmail.com'

const leanDoc = await User.findOne().lean();
leanDoc.domain; // undefined

Если вы используете lean() для повышения производительности, но вам все же нужны виртуальные свойства, у Mongoose есть официально поддерживаемый плагин mongoose-lean-virtuals, который добавляет виртуальные свойства в объекты lean.

Ограничения

Виртуальные свойства Mongoose не хранятся в MongoDB, что означает, что вы не можете выполнять запросы, основанные на виртуальных свойствах Mongoose.

// Will **not** find any results, because `domain` is not stored in
// MongoDB.
const doc = await User.findOne({ domain: 'gmail.com' }, null, { strictQuery: false });
doc; // undefined

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

Загрузка

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

  • Параметр ref, который сообщает Mongoose, из какой модели загружать документы.
  • Параметры localField и foreignField. Mongoose загрузит документы из модели в ref, чей foreignField соответствует localField этого документа.
const userSchema = mongoose.Schema({ _id: Number, email: String });
const blogPostSchema = mongoose.Schema({
  title: String,
  authorId: Number
});
// When you `populate()` the `author` virtual, Mongoose will find the
// first document in the User model whose `_id` matches this document's
// `authorId` property.
blogPostSchema.virtual('author', {
  ref: 'User',
  localField: 'authorId',
  foreignField: '_id',
  justOne: true
});
const User = mongoose.model('User', userSchema);
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
await BlogPost.create({ title: 'Introduction to Mongoose', authorId: 1 });
await User.create({ _id: 1, email: 'test@gmail.com' });

const doc = await BlogPost.findOne().populate('author');
doc.author.email; // 'test@gmail.com'

Виртуальные свойства через параметры схемы

Виртуальные свойства также можно определить непосредственно в параметрах схемы, не используя .virtual:

const userSchema = mongoose.Schema({
  firstName: String,
  lastName: String
}, {
  virtuals: {
    // Create a virtual property `fullName` with a getter and setter
    fullName: {
      get() { return `${this.firstName} ${this.lastName}`; },
      set(v) {
        // `v` is the value being set, so use the value to set
        // `firstName` and `lastName`.
        const firstName = v.substring(0, v.indexOf(' '));
        const lastName = v.substring(v.indexOf(' ') + 1);
        this.set({ firstName, lastName });
      }
    }
  }
});
const User = mongoose.model('User', userSchema);

const doc = new User();
// Vanilla JavaScript assignment triggers the setter
doc.fullName = 'Jean-Luc Picard';

doc.fullName; // 'Jean-Luc Picard'
doc.firstName; // 'Jean-Luc'
doc.lastName; // 'Picard'

То же самое относится и к параметрам виртуальных свойств, например, загрузки виртуальных свойств:

const userSchema = mongoose.Schema({ _id: Number, email: String });
const blogPostSchema = mongoose.Schema({
  title: String,
  authorId: Number
}, {
  virtuals: {
    // When you `populate()` the `author` virtual, Mongoose will find the
    // first document in the User model whose `_id` matches this document's
    // `authorId` property.
    author: {
      options: {
        ref: 'User',
        localField: 'authorId',
        foreignField: '_id',
        justOne: true
      }
    }
  }
});
const User = mongoose.model('User', userSchema);
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
await BlogPost.create({ title: 'Introduction to Mongoose', authorId: 1 });
await User.create({ _id: 1, email: 'test@gmail.com' });

const doc = await BlogPost.findOne().populate('author');
doc.author.email; // 'test@gmail.com'

Дополнительные материалы

  • Виртуальные свойства в схемах Mongoose
  • Загрузка виртуальных свойств
  • Плагин Mongoose Lean Virtuals
  • Начало работы с виртуальными свойствами Mongoose
  • Понимание виртуальных свойств в Mongoose

© 2010 LearnBoost
Licensed under the MIT License.
https://mongoosejs.com/docs/tutorials/virtuals.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API