主题
mongoose操纵MongoDB
一、mongoose是什么?
Mongoose是MongoDB的一个对象模型工具,是基于node-mongoldb-native开发的MongoDB nodes驱动,可以在异步的 环境下执行。同时它也是针对MongoDB操作的一个对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法,让Node JS操作Mongodb数据库变得更加灵活简单。
简单的理解:Mongoose就是一个ORM,专门针对mongodb数据库操作的,类似于Sequelize。
Mongoose中文官网:http://www.mongoosejs.net/
二、Mongoose能做什么?
Mongoose因为封装了对MongoDB对文档操作的常用处理方法,让NodeJS操作MongoDB数据库变得更加容易。 Mongoose为模型提供了一种直接的,基于scheme结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用。
三、node中使用mongoose连接并操纵mongoDB
大致步骤如下:
- npm安装Mongoose,并引入
- 设置集合规则Schema
- 将Schema 编译成一 Model
- 用编译成的Model对MondoDB进行操作
注意:
- 在MongoDB中不需要显式创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建。
- Mongoose 的一切始于 Schema。每个 schema 都会映射到一个 MongoDB collection ,并定义这个collection里的文档的构成。
简单理解:scheme就是sequelize里面的模型model定义的规则,用来定义数据库表(mongodb里面称为集合)结构骨架等信息,通过schema创建集合
(一)安装mongoose
首先得安装mongoDB数据库,并开启服务。
bash
$ npm install mongoose --save
接着,新建db.js文件,引入,mongoose
js
/* db.js */
// 引入mongoose
const mongoose = require('mongoose');
(二)mongoose连接mongoDB
1、连接没有密码的数据库
mongoose.connect("mongodb://localhost/blog")
例如:
js
mongoose.connect("mongodb://localhost/blog")
.then(() => console.log("数据库连接成功"))
.catch((err) => console.log("数据库连接失败", err));
2、连接有密码的数据库
mongoose.connect("mongodb://用户名:密码@localhost/blog")
例如:
js
mongoose.connect("mongodb://localhost/blog")
mongoose.connect("mongodb://localhost/blog")
.then(() => console.log("数据库连接成功"))
.catch((err) => console.log("数据库连接失败", err));
MongoDB设置密码请查看另一篇文章《MongoDB的安装配置与卸载》
说明:
- 1、blog是我们自定义的数据库名字(若blog不存在会自动创建)
- 2、27017是mongoDB数据库的默认端口,可以省略不写
- 3、方法可以传入一个回调函数,也可以不穿,不传返回的是Promise
(三)设置集合规则Schema
Schema是一个对象,用来规定集合(表)的列由哪些字段构成,并且这列的一些存储规则
mongoose下有一个构造函数Schema, 通过实例化这个构造函数,传入相应的字段并设置规则,构造函数就会返回我们创建好的schema
1、创建schema示例
例如:我们要创建一个用户集合
js
// 设置集合规则
const userSchema = new mongoose.Schema({
// 直接指定name字段的数据类型
name: String,
// 也可以通过对象的形式定义的更详细
role: {
type: String,
required: true, // 必填
required: [true, "role必填"], // 字段必填,并自定义检验提示信息,当检验不通过时候,error.messag内返回该信息
default: "默认值", // 默认值, 如果是函数,函数返回值为默认值
// select:"", // 布尔值 指定 query 的默认 projections
validate: {
//自定义检验规则
validate: {
validator: function (v) {
return v.length > 5;
},
message: "role字段长度不符合规则",
},
},
get: (v) => Math.round(v), // 获取器
set: (v) => Math.round(v), // 设置器
/*
字符串 仅mongoose >= 4.10.0。
aliase 是一种特殊的虚拟值,它的 getter 和 setter 会无缝链接到另一个值。
这是一个节省带宽的做法, 你可以储存一个更短的属性名到数据库,同时在调用的时候保持可读性。
*/
alias: "a",
},
tags: [String],
insertTime: { type: Date, default: Date.now },
isPublished: Boolean,
});
2、mongoose 的常用合法 SchemaTypes:
- String 字符串
- Number 数值
- Date 日期
- Buffer 二进制(图片、音视频等文件)
- Boolean 布尔值
- Mixed 一个啥都可以放的 SchemaType , 虽然便利,但也会让数据难以维护
- ObjectId 要指定类型为 ObjectId,在声明中使用 Schema.Types.ObjectId
- Array 数组
- enum 枚举值
更多关于SchemaTypes查看官网:http://www.mongoosejs.net/docs/schematypes.html
(四)通过schema创建模型
上一步我们创建了用户集合规则,现在可以用这个规则来创建一个集合,具体代码如下
js
// user是我们定义的集合名称,会转成复数,userSchema是上面定义的集合规则,返回模型的构造函数User
const User = mongoose.model("user", userSchema);
需要注意:
- 1、
mongoose.model
方法返回一个模型构造函数,我们可以用这个构造函数上的一些方法来对数据库进行操纵。 - 2、这里model的第一个参数是指定我们要创建的集合名称,mongoose会自定将其变成复数(加上S),如 user--->users
- 3、当用mongoose对集合User进行CURD时候,若检测到没有数据库或没有集合,mongoose会自动创建数据库,
mongoose.model
方法会在数据库blog下创建一个集合users
至此,我们可以用模型来对数据库进行操作了
(五)用模型对数据库进行操作
1、新增数据(创建文档)
方式一:
js
// 1. 创建集合类的实例
const users = new User({
name: '张三',
role: '管理员',
tags: ['nodejs', 'html'],
isPublished: true
});
// 2. 保存实例
users.save();
方式二(推荐):
js
// 创建并保存
a、回调函数形式
//直接调用User模型上的静态方法create
User.create({name: "李四",role: "管理员",tags: ["css", "html"],isPublished: true,},(err, doc) => {
// 错误对象
console.log(err);
// 当前插入的文档
console.log(doc);
});
b、Promise的形式(推荐)
// Model.create还支持promise 可以写成下面的形式,或用async await
User.create({name: "王五",role: "超级管理员",tags: ["nodejs", "html"],isPublished: true,})
.then((doc) => console.log(doc))
.catch((err) => console.log(err));
打开数据库图形化工具MongoDBCompass,可以看到刚刚添加的三条数据
2、修改
js
// 修改单个
User.updateOne({name:"张三"}, {name:"张三1",role:"超级管理员"}).then(result => console.log(result))
// 批量修改
User.updateMany({查询条件}, {要更改的值}).then(result => console.log(result))
// 根据id更新
Course.findByIdAndUpdate(id, {
$set: {
author: 'mosh',
isPublished: false
}
}, err => {})
3、删除
js
// 删除单个 findOneAndDelete 只会删除一个如果有多条数据 就删除第一个
Course.findOneAndDelete({}).then(result => console.log(result))
// 删除多个 deleteMany 特别注意:传入{}则删除所有
User.deleteMany({}).then(result => console.log(result))
4、查询
- findOne
- find find方法返回的是一个数组,findOne返回的是一个对象或null
js
// 查所有
Model.find({
name: '张三',
isPublished: true,
age:{ // age大于20且小于30
$gt:20,
$lt:30
},
title:{ // title包含"打豆豆"的
$in:['打豆豆']
}
})
.limit(10) // 每页几条
.skip(1) // 跳过几条,类似于 offset
.sort({name: 1}) // 1 按name升序 -1 按name降序
.select("name tag _id") // 只是展示name tag _id字段
.then(res=>{})
.catch(err=>{})
/* 模糊匹配: */
const { name } = params; // 查询条件参数
if (name) {
let reg = new RegExp(name,'i');
params.name = reg;
}
console.log(params);
let res = await service.tag.findAll(params);
// 查某条
Model.findOne({_id:"61ab6fb1ad5d812392682aed"}).then(res=>{}).catch(err=>{})
5、模型关联
https://www.cnblogs.com/galaxy2490781718/p/13374749.html 关联步骤:
- 1、在创建Schema 时定义联合表和id
- 2、使用populate方法进行关联查询
1、在创建Schema 时定义联合表和id
js
var userSchema=new Schema({
id:ObjectId,
name:String,
age:{type:Number,default:0},
role:[ {
type: ObjectId, // 字段类型是ObjectId(可以理解为存的是roles表的_id值)
ref: 'Role' // 关联Role模型
}]
})
var User=mongoose.model('user',userSchema)
注意:
- 这里用数组对象最好,如果直接是对象,表现出来就是一对一的关系 。
- 如果是数据就是一对多的关系 。
2、使用populate
js
User.find().populate('role').then(res=>{})
注意:
- 没有populate方法的find()会显示role字段绑定id字符串,加上populate就可以将role关联查找出来,把id转换成对应关联表的对象。
问题:
1.设置了获取器但是在获取数据时候不起作用?
解决: 加上 schema.set("toJSON", { getters: true, virtuals: true });
js
const moment = require("moment");
module.exports = (app) => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const TagSchema = new Schema({
name: {
type: String,
required: [true, "标签名称必填"],
},
desc: String,
status: {
type: Boolean,
default: true,
},
// 创建时间
insertTime: {
type: Date,
default: Date.now,
get: (v) => moment(v).format("YYYY-MM-DD"),
},
createUser: String, // 创建人
updateUser: String, // 更新人
updateTime: {
type: Date,
get: (v) => {
// 更新时间
return v ? moment(v).format("YYYY-MM-DD") : null;
},
},
});
TagSchema.set("toObject", { getters: true, virtuals: true }); // toObject时能够转换
TagSchema.set("toJSON", { getters: true, virtuals: true }); // toJson时能够转换
return mongoose.model("Tag", TagSchema);
};
2.mongoose来查询某字段的时候,如何返回指定字段
使用MongoDB的时候需要只查询指定的字段进行返回,也就是类似mysql里面的 SELECT id,name,age 这样而不是SELECT *。在MongoDB里面映射(projection)声明用来限制所有查询匹配文档的返回字段。projection以文档的形式列举结果集中要包含或者排除的字段。可以指定要包含的字段(例如:{field:1})或者指定要排除的字段(例如:{field:0})。默认_id是包含在结果集合中的,要从结果集中排除_id字段,需要在projection中指定排除_id字段({_id:0})。除了_id字段,不能在一个projection中联合使用包含和排除语意。
1)返回所有匹配文档的所有字段
如果没有指定projection,find()方法返回所有匹配文档的所有字段。如下:
js
Model.find({status:true})
将返回Model中status为true的所有数据,是一个数组
2)返回指定字段和_id字段:
一个projection可以明确地指定多个字段。下面的操作中,find()方法返回匹配的所有文档。在结果集中,只有name和age字段,默认_id字段也是返回的。
js
Model.find({status:true},{name:1,age:1})
可以通过在projection中指定排除_id字段将其从结果中去掉,如下例子所示:
js
Model.find({status:true},{name:1,age:1,_id:0})
3)返回除排除掉以外的字段:
这个操作返回所有status为true的文档,在结果中sex字段不返回,其余字段全部返回。
js
Model.find({status:true},{sex:0})
4)数组字段的projection:
$elemMatch
和 $slice
运算符是对数组进行projection
的唯一途径。