mongoose 简介:
mongoose: elegant mongoldb object modeling for node.js
官网是这样解释mongoose。伟哥在 NodeJS 对 MongoDB 封装的文章中虽然对 mongoldb 进行封装后简化了使用,但是对于编写 MongoDB 验证,转换和业务逻辑还是比较复杂的。对于之前使用 Java 习惯封装 DAO 层来后端程序员来,这样编写来操作数据库也是非常不方便。Mongoose 为模型提供了一种直接,基于scheme结构去定义你的数据模型。它内置数据验证,查询构建,业务逻辑钩子等,开箱即用。
开始使用
快速上手 官方的指导先放在这。
大家浏览完官方文档的快速上手之后,使用 mongoose 可以大致分为一下几个步骤:
-
引入 mongoose 模块
-
连接 mongodb 数据库
-
创建 schema
-
创建 model 与数据库中集合(表)建立联系
-
增加数据
- model 实例化
- 实例.save()
-
修改数据 model.updateOne()
-
删除数据 model.deleteOne()
-
查询数据 model.find()
mongodb 存储的是一个json对象,这个schema可以理解成这个对象构造函数,这个schema的写法写过 Vue 和 React 的小伙伴都应该非常熟悉,这个跟 component 的 props 是一样的,前面是属性名称,后面是该属性值的类型。写过TypeScript的这个写法就更熟悉了。当然它也可以指定默认值,这样一看它就跟 Vue和React中 component 中的 props 完全一样了。 schema 一定要与你将来创建model时映射数据中集合的属性对应起来,否则会造成插入或修改失败。
代码实例
/* 引入 mongoose 模块 */
const mongoose = require('mongoose');
/* 与数据库连接 第二参数还是传入,否则会报出一个警告,看着别扭*/
mongoose.connect('mongodb://127.0.0.1:27017/test',{ useNewUrlParser: true });
/* 创建 schema */
const NewsSchema = mongoose.Schema({
title: String,
author: String,
content: String,
status: {
type: Number,
default:1
}
});
/* 创建 model 与 数据库建立联系 */
/* 第一个参数 model 名称,首字母最好大写
* 第二个参数 scheme
* 第三个参数就是与数据库那个collection建立联系
*/
const News = mongoose.model('News', NewsSchema,'news');
/* 增加数据 在news表中增加一条数据*/
/* 创建一个实例 */
const news = new News({title:'News Title',author:'author', content:'News Content', status:1});
/* 调用实例save方法进行数据保存,即使数据库中没有news 这张表,它会先创建表在插入数据*/
news.save(callback)
/* 修改数据 修改status*/
News.updateOne({title:'News Title'},{status:2},callback);
/*删除数据*/
News.deleteOne({title:'News Title'},callback);
/* 查询数据 */
News.find(callback) 或者 News.find({title:/^News/},callback)
mongoose 模块化
通过上一节的了解 使用mongoose操作数据已经可以,但是到我们需要对某一个collection(表)进行操作时我们总不能先吧上面的定义一通,所有我们需要对其进行模块化。封装的时候就跟 Java 中封装的 DAO层一样,不过在这里我们还是叫 model 比较切合 mongoose 中的概念。
mongoose的封装我们分为 2 步走:
- 封装一下如何获取 mongodb 的实例,
- 讲我们用到数据表的 model 都放在 model 文件夹中(当然了这个名字随意)
代码示例:
/* 封装 db.js 获取链接数据库实例 */
const mongoose = require('mongoose');
/*第一参数是数据库连接*/
/*第二个参数根据官方配置,不然那个数据库弹出警告*/
/*第三个参数 回调函数*/
mongoose.connect('mongodb://127.0.0.1:27017/test',{useNewUrlParser: true},(err)=>{
if(err) throw err,
console.log('数据库连接成功')
})
module.exports = mongoose;
/* 封装 modle (Java中的DAO) 以 news 表为例 */
const mongoose = require('./db.js');
const NewsSchema = mongoose.Schema({
title:String,
author:String,
content:String,
status:Number
})
module.exports = mongoose.model('News', NewsSchema, 'news');
/* 使用 */
const NewsModel = require('./model/news.js');
NewsModel.find({},(err,doc)=>{
if(err) throw err;
console.log(doc);
})
Mongoose 预定义修饰符 Getter 与 Setter
Mongoose 提供的一些预定义修饰符可以帮我们存取数据进行一些格式化的操作。
Mongoose 本身提供了一些预定义的修饰符,设置这些属性在数据存入数据库的时候就会有对应的操作。
// mongoose 预定义修饰符
trim:true //去首尾空格
lowercase:true //转化为小写
uppercase:true //转化为大写
var UserSchema=mongoose.Schema({
name:{
type:String,
trim:true //去首尾空格
},
age:Number,
status:{
type:Number,
default:1,
lowercase:true
}
})
Mongoose 也提供了自定义修饰符 Setter 和 Getter,Setter 会在数据存入数据库时进行格式化操作,Getter只是在输出实例的时候会进行定义的操作,读数据库的数据没有任何影响(没什么用)。
上代码:
// 加入我们要对 url 进行格式化,如果数据以 http:// 开头我们原样存入,如果不以 http:// 开头,添加之后再存入数据库
const ArticleSchema = mongoose.Schema({
title:String,
author:String,
img:{
type:String,
set(params){
if(!params) return params;
return /^http:\/\//.test(params) ? params : 'http://' + params
},
get(params){
return 'mongodb:' + params;
}
}
});
const article2 = new Article({
title:'武汉加油',
author: '人民日报',
img:'wuhan/pic02'
});
// 这样存入数据库的数据就是 http://wuhan/pico2
console.log(article2.img) // mongo:wuhan/pic02 ---- getter就是这样用,所有没啥用处
Mongoose 内置 CURD 方法,扩展 Mongoose Model 的静态方法和实例方法
// 内置 CURD 方法
model.deleteMany()
model.deleteOne()
model.find()
model.findById()
model.findByIdAndDelete(),
model.findByIdAndRemove(),
model.findByIdAndUpdate(),
model.findOneAndDelete(),
model.findOneAndRemove(),
model.findOndAndUpdate(),
model.replaceOne(),
model.updateMany(),
model.updateOne()
ArticalModule.updateOne({'title':'武汉加油'},{$set:{'title':'中国加油,武汉加油'}})
在 mongoose 方法基础上进行封装,例如 我们定义一个按照 title 查找的方法
Mongoose 分为静态方法和实例方法两种,这个跟各编程语言的静态和实例方法一个意思
// 静态方法
ArticleSchema.static({
findByTitle(title,cb){
this.find({title},function(err,docs){
cb(err,docs)
})
}
})
// 实例方法
ArticleSchema.method({
console.log('这是一个实例方法');
console.log(this.name);
})
Mongoose 数据校验
mongoose 聚合管道 (连表查询)
聚合管道其实就是mongodb的连表查询
举个例子:现在有两张表,订单表(order)和订单清单表(orderItem)
现在进行查询获取所有订单总价个大于90的订单号订单项清单
Order.aggregate([
{
$lookup:{
from:'orderItem', // 有集合
localField: 'id', // 做集合连接键
foreignFileId: 'order_id', // 有集合外键
as:'items' //查询到集合的别名
},
$match:{
'all_price' : {$get:90}} 大于九十
}
}
])
// 上面的写成SQL语句就是
// select * from order right join orderItem where order.id = orderItem.order_id and order.all_price > 90 这样理解起来localField 和 foreignField 也许就简单了
上面是两个表 多表查询呢?
//有三张表
//分类表
articlecate: {
id: Schema.Types.ObjectId,
title:String,
description: String,
add_time: Date
}
//文章表
article:{
id:Schema.Types.ObjectId,
cid:Schema.Types.ObjectId,
title:String,
description:string,
author_id:Schema.Types.ObjectId,
author_name:String,
content:String,
add_addtime:Date
}
//用户表
user:{
id:Schema.Types.ObjectId,
username:String,
password:String,
name:String,
age:Number,
sex:String,
tel:String,
add_time:Date
}
// 查询文章信息,并显示文章分类,以及作者信息
ArticleModule.aggregate([
{
$lookup:{
from: 'articlecate',
localField: 'cid',
foreignField:'id',
ad:articlecate
}
}{
$lookup:{
from: 'user',
localField:'auth_id',
foreignField:'id',
as:user
}
},{
$match:{
id: Schema.Type.ObjectId('123')
}
}
],(err,docs)=>{
console.log(JSON.stringify(docs))
})
管道管道,直接写就OK了。还有一直用写法是用Populate来进行多表查询,但是这种写法性能上不如 $lookup,但是写法上简单的。它的使用必须在创建 schema 时就要创建外键(跟关系性数据快快要一致了),具体用法可以看下面教程,写的简单易懂,主要是作者头像很好看 hhh
详解 mongoose Populate
其他聚合需要了解的内容
网友评论