标题:Mongoose 中如何使用 Virtuals 进行数据虚拟化
摘要:在使用 Mongoose 操作 MongoDB 数据库时,有时需要将不同集合的数据进行关联查询,但是又不想在数据库中建立实际的关联关系,这时就可以使用 Virtuals 进行数据虚拟化。本文将详细介绍 Mongoose 中 Virtuals 的使用方法,包括定义 Virtuals、使用 getter 和 setter 方法、以及与 Populate 方法结合使用的示例。
1. Virtuals 概述
Mongoose 中的 Virtuals 是指在 Mongoose 模型中定义的虚拟属性,这些属性不会被存储在 MongoDB 中,而是在查询时动态生成,从而实现对数据的虚拟化。
使用 Virtuals,可以使得不同集合的数据进行关联查询变得更加容易,同时也可以对查询结果进行一些计算和转换操作,满足不同业务需求。
2. 定义 Virtuals
Mongoose 中定义 Virtuals 非常简单,只需要在 Schema 选项中增加一个 virtuals 字段,并在该字段中定义虚拟属性的名称和 getter 方法即可。
示例代码如下:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, age: { type: Number, }, gender: { type: String, enum: ['male', 'female', 'unknown'], default: 'unknown', }, }); // 定义一个计算属性 `info`,通过 `name` 和 `age` 计算得到 userSchema.virtual('info').get(function() { return `${this.name} is ${this.age} years old`; }); const User = mongoose.model('User', userSchema);
上述代码定义了一个 User 模型,其中包含了三个实际字段(name、age 和 gender),以及一个虚拟字段 info。虚拟字段 info 的值是通过在 getter 方法中计算得到的,其内容由 name 和 age 两个实际字段组成。
3. 使用 getter 和 setter 方法
在上述例子中,我们定义的是只读的虚拟字段,即只能通过 getter 方法获取它的值,不能修改其值。但是有些场景下,我们需要定义可读写的虚拟属性,这时就需要使用到 getter 和 setter 方法。
示例代码如下:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); const postSchema = new mongoose.Schema({ title: { type: String, required: true, }, content: { type: String, required: true, }, }); const commentSchema = new mongoose.Schema({ postId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Post', }, content: { type: String, required: true, }, }); // 定义一个可读写的虚拟属性 `post`,通过查询得到相关联的 `Post` 文章 commentSchema.virtual('post', { ref: 'Post', localField: 'postId', foreignField: '_id', justOne: true, set: function(post) { this.postId = post._id; }, }); const Post = mongoose.model('Post', postSchema); const Comment = mongoose.model('Comment', commentSchema);
上述代码定义了两个模型:Post 和 Comment,其中 Comment 模型的虚拟属性 post 是一个可读写的属性,它的值是动态查询得到的,我们可以通过 setter 方法将查询的结果保存回数据库中。在这个例子中,我们通过 Comment 模型的 postId 字段查询相关联的 Post 文章,并将查询结果保存在虚拟字段 post 中。
4. 与 Populate 方法结合使用
在前面的章节中,我们已经介绍了如何使用 Virtuals 去关联不同集合的数据。但当我们需要访问关联集合中的具体数据时,可以结合使用 Populate 方法。
示例代码如下:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); const authorSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, required: true, unique: true, }, }); const bookSchema = new mongoose.Schema({ title: { type: String, required: true, }, author: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Author', }, }); // 定义一个可供查询的计算虚拟属性 `authorName`,通过 `author` 字段查询 `Author` 集合得到 bookSchema.virtual('authorName', { ref: 'Author', localField: 'author', foreignField: '_id', justOne: true, options: { select: 'name' }, }); const Author = mongoose.model('Author', authorSchema); const Book = mongoose.model('Book', bookSchema); (async () => { await mongoose.connect('mongodb://localhost/test', { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false, }); const author = await Author.create({ name: 'Suzanne Collins', email: 'suzanne@gmail.com', }); await Book.create({ title: 'The Hunger Games', author: author._id, }); const books = await Book.find().populate('authorName'); console.log('books:', books); })();
上述代码定义了两个模型:Author 和 Book,其中 Book 模型的 author 字段是一个 ObjectId 类型的字段,它引用了 Author 集合的 _id 字段。我们在 Book 模型中定义了一个可供查询的虚拟属性 authorName,通过将 localField 设置为 author,将 foreignField 设置为 _id,从而查询出 Author 集合中对应的 name 字段。最后我们通过 populate 方法,将查询结果与 Book 集合中的数据合并,并输出结果。
5. 总结
本文详细介绍了 Mongoose 中 Virtuals 的使用方法,包括定义 Virtuals、使用 getter 和 setter 方法、以及与 Populate 方法结合使用的示例。使用 Virtuals 可以方便地对数据进行关联查询和计算操作,对于需要对数据进行前端展示和业务处理的场景非常有用。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654c54ad7d4982a6eb5e5450