Mongoose介绍
面对这样的困境, 编写MongoDB验证,转换和业务逻辑是非常麻烦的. 所以发明了Mongoose
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const Cat = mongoose.model('Cat', { name: String });
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
Mongoose为模型提供了一种直接的,基于scheme结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用
Mongoose是一个优雅的NodeJS对象文档模型Object Document Module,通过关系型数据库的思想来设计非关系型数据库,它基于mongodb驱动,简化操作
Mogoose对mongodb做了大量的封装
- Scheme 对应了表
- Module 对应了数据库集合
- Documents 文档对象
初始化&安装
npm init -y
npm i express mongodb mongoose -s
使用
// 引入模块
const mongoose = require('mongoose')
// 连接、配置数据库,返回一个待定的连接
mongoose.connect('mongodb://192.168.31.107:27017', {
user: 'maxuan',
pass: '601109',
dbName: 'blog',
autoIndex: false,
useNewUrlParser: true
})
// 获取数据库对象
const db = mongoose.connection
// 连接失败的警告
db.on('error', console.error.bind(console, 'connection error:'))
// 连接成功
db.once('open',async ()=> {
// we are connected!
// 定义一个Schema = 表
const blogSchema = new mongoose.Schema({
title: String,
author: String,
body: String,
comments: [
{
body: String,
date: Date
}
],
date: {
type: Date,
default: Date.now
},
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
})
// 把Schema编译为一个模型
const blogs = mongoose.model('blogs', blogSchema)
// 通过模型对数据库的集合进行操作
})
在配置连接后面配置数据库名称,如果不填写,会自动生成test数据库
在连接最新版mongodb时会有一个报错,需要添加 useUnifiedTopology: true 配置支持
mongoose没有insertOne()方法,插入一条数据就在数组内传入一个对象
创建的集合名会被转为全小写,如果名字为复数的保持不变,如果为单数,则自动判断单词添加s或者es
运行 server.js,打印数据插入成功,刷新数据库,集合创建完成,数据插入成功
以下增删改查操作都要在 db.once('open',async ()=> { } 内的模型下完成
Query API文档
增加
await blogs.insertMany([
{
title: 'Vue',
author: 'youyuxi',
body: 'Vue是一个轻量级的高效的前端框架',
comments: [
{
body: '说得对',
date: new Date()
}
],
hidden: true,
meta: {
votes: 10,
favs: 200
}
},
{
title: 'React',
author: 'facebook',
body: 'React是一个更厉害的前端框架',
comments: [
{
body: '说得不完全对',
date: new Date()
}
],
hidden: false,
meta: {
votes: 20,
favs: 400
}
}
])
console.log('数据插入成功');
查询
let r = await blogs.find({author: 'youyuxi'})
console.log(r)
/*
[
{
meta: { votes: 10, favs: 200 },
_id: new ObjectId("616c477f330f6921c48c5baf"),
title: 'Vue',
author: 'youyuxi',
body: 'Vue是一个轻量级的高效的前端框架',
comments: [ [Object] ],
hidden: true,
date: 2021-10-17T15:55:43.727Z,
__v: 0
}
]
*/
这里获取到的id如果是new ObjectId,需要前端通过 r[0]._id.toHexString() 转换为字符串,将这个字符串返回服务器可用于查询或其他操作
调用mongoose的查询 and() api方法
let r = await blogs.find().and([
{
author: 'facebook'
},
{
title: 'Vue'
}
])
console.log(r);
更新
更新并返回更新状态
r = await blogs.where({author: 'youyuxi'}).updateOne({title: 'Vue.js'})
console.log(r)
/*
{
acknowledged: true,
modifiedCount: 1, upsertedId: null,
upsertedCount: 0,
matchedCount: 1
}
*/
更新并返回更新结果
r = await blogs.findOneAndUpdate({author: 'youyuxi'},{$set:{title: 'Vue.js'}})
console.log(r);
/*
{
meta: { votes: 10, favs: 200 },
_id: new ObjectId("616c4898ab1f6d1fc43fced6"),
title: 'Vue.js',
author: 'youyuxi',
body: 'Vue是一个轻量级的高效的前端框架',
comments: [
{
body: '说得对',
date: 2021-10-17T16:00:24.138Z,
_id: new ObjectId("616c4898ab1f6d1fc43fced7")
}
],
hidden: true,
date: 2021-10-17T16:00:24.148Z,
__v: 0
}
*/
删除
r = await blogs.deleteOne({author: 'youyuxi'})
console.log(r);
// { deletedCount: 1 }
定义方法
实例方法
定义在Schema对象上的方法,this后需要通过 model('blogs') 调用模型对象,必须定义在编译blogs模型前面,且因为this指向不能用箭头函数
使用的时候要new一个模型实例,并配置实例方法find内对应的参数,然后在模型实例上调用这个方法
blogSchema.methods.findAuthor = function() {
// 返回一个对模型查询的条件
return this.model('blogs').find({author: this.author}).exec()
}
// 把Schema编译为一个模型
const blogs = mongoose.model('blogs', blogSchema)
// 获取模型实例并配置查询参数
let b = new blogs({author: 'youyuxi'})
// 调用实例方法返回结果
r = await b.findAuthor()
console.log(r);
/*
[
{
meta: { votes: 10, favs: 200 },
_id: new ObjectId("616c4898ab1f6d1fc43fced6"),
title: 'Vue',
author: 'youyuxi',
body: 'Vue是一个轻量级的高效的前端框架',
comments: [ [Object] ],
hidden: true,
date: 2021-10-17T16:00:24.148Z,
__v: 0
}
]
*/
__v: 0 — 用来在 save 文档时作为一个查询条件,以免在从「取出数据」到「save 数据」这段时间里,数据被其他进程修改,导致最后修改出现冲突
此处用的是find,获取到的结果可能是多个所以返回的是个数组,如果目标是返回提个唯一的结果,使用findOne
定义实例方法后的exec(callback)方法,作用是在获取到数据调用回调函数,这个方法可用于
静态方法
定义在模型上的方法,模型对象上直接调用静态方法并传入参数,返回给 r,必须定义在编译blogs模型前面,且因为this指向不能用箭头函数
blogSchema.statics.findTitle = function(title) {
return this.findOne({title: title}).exec()
}
const blogs = mongoose.model('blogs', blogSchema)
r = await blogs.findTitle('Vue')
console.log(r);
虚拟属性
虚拟属性是使用在返回结果r对象上的处理函数,相当于Vue的计算属性,是对返回结果进行处理的
blogSchema.virtual('getContent').get(function() {
return `${this.author}发布了一个叫${this.title}的前端框架`
})
// 把Schema编译为一个模型
const blogs = mongoose.model('blogs', blogSchema)
r = await blogs.findTitle('Vue')
// ------------------------↓↓↓↓↓↓↓
console.log(r.getContent)
// youyuxi发布了一个叫Vue的前端框架