第十四节 : mongose
1. mongoose的简介
mongoose是基于Node.js的用于操作MongoDB数据库的第三方的模块
mongoose库简而言之就是在node环境操作MongoDB数据库的一种便捷的封装,一种对象模型工具,Mongoose将数据库中的数据转换为JavaScript对象以供你在应用中使用
2. 通过示例了解mongoose的使用
2.1 安装mongoose
npm install mongoose -S
2.2. mongoose的基本使用
// 引入mongoose mongoose的依赖中
var mongoose = require("mongoose");
// 链接数据库
mongoose.connect("mongodb://localhost/students");
// 创建Schema, 就是先规定了一些集合中的字段
let Schema = new mongoose.Schema({
username:"String",
age:Number,
sex:"String"
})
// 创建一个模型,就是一个类
var Student = mongoose.model("student",Schema)
// 实例化对象
var xiaoming = new Student({
sname:"小明",
sex: "男",
age: 12
})
// 保存对象
xiaoming.save()
3.详细理解mongoose的使用
3.1 连接数据库
mongoose.connect("mongodb://127.0.0.1:27017/数据库名",function(err){
if(err){
throw err // 如果数据库有错误,那么久抛出数据库连接的错误
}else{
console.log("数据库连接成功")
}
})
3.2 创建Schema
3.2.1 认识schema
每个 schema 都会映射到一个 MongoDB collection ,并定义这个collection里的文档的构成。
var schema = new mongoose.Schema({
字段名: 类型,
字段名: 类型
})
例如;
var Schema = new mongoose.Schema({
username:"String",
age:Number,
sex:"String"
})
document 里每个属性的类型都会被转换为 在 Schema
里定义对应的 SchemaType
。
也就是说如果你在像数据库中存入数据的时候,存入的类型和Schema
限定的类型不同, 则会发生隐式类型转换,如果转换不了则会报错.
3.2.2 Schema Type类型有
字段的类型
String
Number
Date
Buffer 二进制
Boolean
Mixed 混合类型
ObjectId
Array
3.2.3 默认值.
如果需要指定默认值,那么Schema中的字段值将不再是类型,而是一个对象
对象的type
属性为字段类型, default
为默认值
示例:
var Schema = new mongoose.Schema({
username:String,
age:{
type:Number,
default: 18
},
sex:{
type:String,
default:"男"
}
})
上面的示例是使用固定值作为默认值
除了使用固定值作为默认值外,还可以使用动态值作为默认值例如时间
示例
var Schema = new mongoose.Schema({
username:String,
age:{
type:Number,
default: 18
},
sex:{
type:String,
default:"男"
},
regTime:{
type:Date,
default: Date.now
}
})
3.2.4 修饰符 trim;
格式化去掉字符的空格
var Schema = new mongoose.Schema({
username:{
type:String,
trim:true
}
})
3.2.5 验证器
所有数据类型都有的验证器required
有配置required
验证器的字段为必须的.
数字类型特有的验证器max
,min
max
,min
验证用户传递的数字的最大最小值.
字符串枚举验证器 enum
enum
验证器就是验证用户输入的字符串,是不是在enum
中罗列的字段,否则机会报错
字符串正则验证 match
match
验证器的值是一个正则,验证用户输入的是否通过正则匹配
自定义验证器validate
validate
自定义验证器的值是一个函数, 返回一个布尔值,true
为验证通过, false
为验证不通过
3.3 根据Schema创建模型model
概述:model模型是一种根据schema创建出来的模型,具备数据库操作的能力
我们在使用Mongoose的时候,一定要记住,一个mongoose的model就对应一个集合,创建一个model的时候,就是使用mongoose.model()
var student = mongoose.model("模型名称",Schema,"集合名称")
集合名称与模型名称保持一致
通常我们不传第三个参数
var student = mongoose.model("类的名字",Schema)
有了模型以后可以通过模型直接读取数据
3.4.根据模型创建实例,通过实例可以写入数据
概述:
根据模型创建出一个实例,实例具备数据库操作能力,通常用于写数据(新增,修改,删除),能会影响数据库的操作
var xiaoming = new Student({
username:"小明",
age:18,
})
// 保存数据
xiaoming.save()
4. mongoose的数据库操作(增删改查)
4.1 查询数据/读取数据
find()方法:根据条件对象进行数据查询,可以找到多条数据
模型.find({条件},function(err,data){
// data 是从 数据库中读取的数据
// find()方法查询出来的数据一定是一个数组,即使没有数据也是一个空数组
})
findOne() 方法: 更加条件查询一条数据
模型.findOne({条件},function(err,data){
// data 是从 数据库中读取的数据
// find()方法查询出来的数据是一个当个的文档对象
})
findById()查询一条数据(通过ID找指定的数据)
模型.findById("id",function(err,data){
// findById 找出来的数据是一个对象,因为只是找一个数据
})
exec()另一种常用的写法(为了更好的实现链式调用)
模型.find(()).exec(function(err,data){
})
4.2 新增数据
实例.属性名= 属性值
....
实例.save(function(err){ // 将数据保存到数据库中
// err 数据保存失败
})
注意Schema中没有定义的字段,是不会写入数据库的,虽然不会报错
4.3 删除数据
思路
- 先查询到要被删除的数据
- 调用remove()方法删除数据
模型.findById("id").exec(function(err,data){
// 如果没有报错,就是先查询到指定的数据data
// 然后删除数据
data.remove(function(err,data){
// err在数据删除失败后会有值
// data是删除的数据
})
})
4.4 修改数据
思路
找出需要修改的数据
将数据修改以后保存会数据库
模型.findById("id").exec(function(err,data){
// 如果没有报错,就是先查询到指定的数据data
// 然后修改数据
data.name = "新的值";
data.age = "新的值";
data.save(function(err){
// err在修改错误时报错有值
})
})
5. Mongoose静态方法和动态方法(自定义方法)
Mongoose最好用的地方就是可以提供静态方法和动态方法
静态方法就是类能够调用的方法 如
Math.random()
动态方法就是实例能够调用的方法
xiaoming.sayHello()
在Mongoose中很神奇的地方就是在静态方法中能够返回Mongoose的Model的实例,这个实例又可以调用动态的方法
5.1 静态方法
静态方法通过Schema上的statics属性定义
静态方法定义在Schema上,在定义mongoose.model类后,通过这个类来调用这个静态方法
静态方法中的this指的就是当前这个集合,可以通过find()查找
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/students")
// 创建Schema
var StudentSchema = new mongoose.Schema({
name: String,
age: Number,
sex: String
})
// 在StudentSchema对象上定义静态方法,静态方法要定义在Schema上
StudentSchema.static.findByName = function(name){
// 静态方法中的this指代这个数据结合,就是students
this.find({name},function(err,results){
console.log(results);
})
}
// 创建一个类,mongoose的model
var Student = mongoose.model("student",StudentSchema);
// 通过类打点调用静态方法
Student.findByName("小明")
静态方法的功能,我们可以通过静态方法去修改数据
var mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/wuwei")
// 创建Schema
var StudentSchema = new mongoose.Schema({
name: String,
age: Number,
sex: String
})
// 静态方法
StudentSchema.statics.findByName = function(name){
// 静态方法中的this指代这个数据表,就是Peoples
this.find({name},function(err,results){
console.log(results);
})
}
// 静态方法
peopleSchema.statics.changeSexByName = function(name){
this.find({name},function(err,result){
var user = result[0];
if(user.sex === '男'){
user.sex = "女";
}else{
user.sex = "男"
}
// 持久化保存
user.save()
})
}
// 创建一个类,mongoose的model
var Student = mongoose.model("People",StudentSchema);
// 通过类打点调用静态方法
Student.findByName("小明")
5.2 动态方法
动态方式是通过Schema上的 methods方法定义
无论静态方法还是动态方法都是定义在Schema上面,只是调用的主体不同,静态方法的调用主体是类,动态方法的调用主体是实例
其实静态方法中返回的result数组中就是实例,所有我们要使用动态方法可以先使用静态方法通过回调拿到对应的实例以后在使用动态方法
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/wuwei")
var StudentSchema = new mongoose.Schema({
name: String,
age: Number,
sex: String,
scores: [{ preject: String, socre: Number }],
nation: { type: String, default: "汉" }
})
// 静态方法
StudentSchema.statics.findByName = function (name, callback) {
this.find({ name }, function (err, result) {
// 通过回调函数将查询到的实例数组返回
callback(result)
})
}
// 动态方法
StudentSchema.methods.sayHello = function () {
// 这里的this指的是对应的实例
console.log("当当当当!,我叫" + this.name + ",我是一个" + this.sex + "人.")
}
var Student = mongoose.model("student", StudentSchema);
// 通过静态方法包动态方法来调用
// 通过类调用静态方法先找到小明
Student.findByName("小明", function (result) {
// console.log(result)
// 通过回调函数拿到小明的实例
var user = result[0];
// 在通过实例调用动态方法
user.sayHello()
})
mongoose中如果要查询数据,一般来说使用静态方法,如果要改变值,直接对象打点更改属性,然后save就可以了
可以理解静态方法是操作集合,动态方法是操作某一个文档的
如果如果希望修改数据,我们没有必要封装一个静态方法我们可以使直接通过类的find方法,来查询修改数据
Student.find({"name":"小明"},function(err,students){
var student = students[0];
student.name = "小红";
student.save();
})
如果希望只拿到一条数据可以使用findOne查询
Student.findOne({"name":"小明"},function(err,student){
student.name = "小红";
student.save();
})
如果希望删除所有名字叫小明的文档
Student.find({"name":"小明"},function(err,students){
students.forEach(item => {
item.remove();
})
})
6 连表查询
数据库中不可能只有一个集合,如果有多个集合,肯定会有多个类,此时他们至间或多或少有一些联系,比如课程和学生之间就是这样的关系 ,多对多关系
一个学生可以选择多个课程,一个课程可以被多个
MongoDB 3.2 之后,也有像 sql 里 join 的聚合操作,Mongoose,拥有更强大的 populate()
,
可以让你在别的 collection 中引用 document。
Population 可以自动替换 document 中的指定字段,替换内容从其他 collection 获取。 我们可以填充(populate)单个或多个 document、单个或多个纯对象,甚至是 query 返回的一切对象。
看下面的示例:
6.1 首先Schema的处理
在Schema指定相关关联的集合
// 作者Schema
let UseSchema = mongoose.Schema({
_id:mongoose.Schema.Types.ObjectId,
username:String,
age: Number,
articles:[
{
type:mongoose.Schema.Types.ObjectId,
ref:"Article"
}
]
})
// 文章Schema
let ArticleSchema = mongoose.Schema({
title:String,
author:{
type:mongoose.Schema.ObjectId,
ref:"User"
},
fans:[{
type:mongoose.Schema.ObjectId,
ref:"User"
}]
})
// 通过Schema 创建模型
let User = mongoose.model("User",UseSchema);
let Article = mongoose.model("Article",ArticleSchema);
6.2 保存是关联_id
在保存数据是关联指定的id
// 保存作者和文章
let user = new User({
_id: new mongoose.Types.ObjectId(),
username:"阿冠",
age:18,
articles:[]
})
user.save(function(err){
if(err){
console.log("作者保存失败");
return
}
console.log("作者保存成功");
// 定义文章的保存
// 让文章author关联指定的用户
let article = new Article({
title:"带你看海的星星",
author:user._id,
fans:[user._id]
})
article.save(function(err, data){
if(err){
console.log("文章保存失败");
return
}
console.log("文章保存成功");
// 让用户的articles关联指定的文章
user.articles.push(article);
user.save().then(data=>{
console.log(data);
}).catch(err => {
console.log(err);
})
})
})
注意:
- 如果需要使用连表查询,ObjectId字段不能是手动插入,必须是自动生成