镇江企业网站建设,西安汇友网站建设,商会网站建设方案书,中英文网站建站1.简介 Mongoose是一个让我们可以通过Node来操作MongoDB的模块。Mongoose是一个对象文档模型(ODM)库,它对Node原生的MongoDB模块进行了进一步的优化封装#xff0c;并提供了更多的功能。在大多数情况下#xff0c;它被用来把结构化的模式应用到一个MongoDB集合#xff0c;并…
1.简介 Mongoose是一个让我们可以通过Node来操作MongoDB的模块。Mongoose是一个对象文档模型(ODM)库,它对Node原生的MongoDB模块进行了进一步的优化封装并提供了更多的功能。在大多数情况下它被用来把结构化的模式应用到一个MongoDB集合并提供了验证和类型转换等好处mongoose中的对象 Schema 模式对象Schema对象定义约束了数据库中的文档结构Model 模型对象Model对象作为集合中的所有文档的表示相当于MongoDB数据库中的集合collectionDocument 文档对象Document表示集合中的具体文档相当于集合中的一个具体的文档
mongoose的好处
可以为文档创建一个模式结构(Schema)可以对模型中的对象/文档进行验证数据可以通过类型转换转换为对象模型可以使用中间件来应用业务逻辑挂钩比Node原生的MongoDB驱动更容易
安装
npm i -S mongoose2.连接数据库 config/db.config.js
// 1.引入mongoose
const mongoose require(mongoose);// 2.连接mongodb数据库
// 指定连接数据库后不需要存在当你插入第一条数据库后会自动创建数据库
/*
mongoose.connect(mongodb://数据库地址:端口号/数据库名,{useMongoClient:true})
如果端口号是默认端口号(27017)则可以省略不写
*/
mongoose.connect(mongodb://127.0.0.1:27017/ds2, {useNewUrlParser: true,useUnifiedTopology: true,useCreateIndex: true,
})// 3.监听mongodb数据库的连接状态
// 绑定数据库连接成功事件
mongoose.connection.once(open, function () {console.log(连接成功);
});
// 绑定数据库连接失败事件
mongoose.connection.once(close, function () {console.log(数据库连接已经断开);
});// 4.断开数据库连接(一般不用)
mongooes.disconnect();注:MongoDB数据库一般情况下只需要连接一次连接一次后除非项目停止服务器关闭否则连接一般不会断开 在bin目录下的www文件中使用直接require(“…/config/db.config.js”)进行数据库连接的启动
3.创建模式对象和模型对象 数据库中的 Schema为数据库对象的集合。schema 是 mongoose 里会用到的一种数据模式可以理解为表结构的定义每个 schema会映射到 mongodb 中的一个 collection它不具备操作数据库的能力。
每个 schema 都会映射到一个 MongoDB collection 并定义这个collection里的文档结构支持的字段类型
类型作用String定义字符串Number定义数字Date定义日期Buffer定义二进制Boolean定义布尔值Mixed定义混合类型ObjectId定义对象IDArray定义数组
model/UserModel.js
const mongoose require(mongoose)
const Schemamongooes.Schema;
//创建模式对象
const UserTypenew Schema({name:{type: string,//添加约束保证数据的完整性让数据按规矩统一require: true},age:Number,gender:{type:String,// 默认值default:female},address:String
})//创建模型对象
//通过Schema来创建Model
//Model代表的是数据库中的集合通过Model才能对数据库进行操作
//mongoose.model(modelName,schema)
//建立映射关系students是集合,mongoose会自动将集合变成复数比如student会变成students
//大写也会被自动转换为小写比如Users会变成users
const UserModelmongoose.model(UserModel,UserTypeuser);
//第一个参数表示创建的集合的名称第二个参数表示利用的模式对象第三个参数是强行指定集合名称module.exports UserModel 4.文档新增 4.1 save()
操作的是文档 案例
var mongoose require(mongoose)
const UserModel require(../model/UserModel);//链式调用 通过new 一个Model创建一个 document
new UserModel({name:小明,age:18}).save((err,docs) {if(!err){console.log(docs)res.send({code: 200,data: {id: docs._id,},})//{ _id: 6017bd1cf4cc8544d8ed2a8a, name: 小明, age: 18, __v: 0 }}
}) 4.2 create()
操作模型Model.create(doc(s), [callback])参数 [doc(s)]文档对象或文档对象数组 [callback]回调函数
var mongoose require(mongoose)
const UserModel require(../model/UserModel);UserModel.create({name:小明,age:18},{name:小红,age:10},(err,doc1,doc2) {if(!err){console.log(doc1)//{ _id: 6017be2d77c8dd01242624bb, name: 小明, age: 18, __v: 0 }console.log(doc2)//{ _id: 6017be2d77c8dd01242624bc, name: 小红, age: 10, __v: 0 }}
})其它
//Model.createOne(doc, [callback]); 创建一个对象
//Model.createMany(doc, [callback]); 创建多个对象
// -doc是需要插入的文档
// -callback(err) 是回调函数可以用来提示是否创建成功了
4.3 insertMany()
Model.insertMany(doc(s), [options], [callback])
返回值为一个数组
案例
UserModel.insertMany({name:小明,age:18},{name:小芳,age:14},(err,docs) {if(!err){console.log(docs)/*[{ _id: 6017befb5c36d64d08b72576, name: 小明, grades: 68, __v: 0 },{ _id: 6017befb5c36d64d08b72577, name: 小芳, grades: 94, __v: 0 }]*/}
})5.文档查询 _idnamegrades__v6017befb5c36d64d08b72576小明6806017befb5c36d64d08b72577小芳9406017c455ba09d355a49ec8eb小红5206017c455ba09d355a49ec8ec小刚460
5.1 find() Model.find(conditions, [projection], [options], [callback]) 参数 conditions查询条件 [projection]控制返回字段 [options]配置查询参数 [callback]回调函数–function(err,docs){} 案例
var mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,(err) {if(!err){var schema new mongoose.Schema({name:String,grades:Number})var stuModel mongoose.model(grades,schema)//查询所有数据stuModel.find((err,docs) {if(!err){console.log(docs)}}) /* [{ _id: 6017befb5c36d64d08b72576, name: 小明, grades: 68, __v: 0 },{ _id: 6017befb5c36d64d08b72577, name: 小芳, grades: 94, __v: 0 },{ _id: 6017c455ba09d355a49ec8eb, name: 小红, grades: 52, __v: 0 },{ _id: 6017c455ba09d355a49ec8ec, name: 小刚, grades: 46, __v: 0 }]*///查询成绩大于60以上的数据stuModel.find({grades:{$gte:60}},(err,docs) {if(!err){console.log(docs)}})/*[{ _id: 6017befb5c36d64d08b72576, name: 小明, grades: 68, __v: 0 },{ _id: 6017befb5c36d64d08b72577, name: 小芳, grades: 94, __v: 0 }]*///查询成绩大于60以上且名字里存在‘芳’的数据stuModel.find({name:/芳/,grades:{$gte:60}},(err,docs) {if(!err){console.log(docs)}})/*[* { _id: 6017befb5c36d64d08b72577, name: 小芳, grades: 94, __v: 0 }* ]*///查询名字里存在‘明’的数据且只输出‘name’字段//_id默认会返回stuModel.find({name:/明/},{name:1,_id:0},(err,docs) {if(!err){console.log(docs)}})// [{name: 小明}]//跳过前两条数据并限制只输出一条数据stuModel.find(null,null,{skip:2,limit: 1},(err,docs) {if(!err){console.log(docs)}})/*[{ _id: 6017c455ba09d355a49ec8eb, name: 小红, grades: 52, __v: 0 }*/}
})5.2 findById()
Model.findById(id, [projection], [options], [callback])案例
var mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,(err) {if(!err){var schema new mongoose.Schema({name:String,grades:Number})var stuModel mongoose.model(grades,schema)//保存查询数据的_idvar aIDArr []//查询所有数据stuModel.find((err,docs) {if(!err){docs.forEach((item,index,arr){aIDArr.push(item._id)})//显示第 0 个元素的所有字段stuModel.findById(aIDArr[0],(err,doc){if(!err){console.log(doc)}})// { _id: 6017befb5c36d64d08b72576, name: 小明, grades: 68, __v: 0 }//显示第 0 个元素且只输出name字段stuModel.findById(aIDArr[0],{name:1,_id:0},(err,doc){if(!err){console.log(doc)}})// { name: 小明 }//显示第 0 个元素且输出最少的字段(_id默认输出)stuModel.findById(aIDArr[0],{lean:true},(err,doc){if(!err){console.log(doc)}})// { _id: 6017befb5c36d64d08b72576 }}})}
})5.3 findOne()
返回查询到的数据的第一个Model.findOne([conditions], [projection], [options], [callback])案例
var mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,(err) {if(!err){var schema new mongoose.Schema({name:String,grades:Number})var stuModel mongoose.model(grades,schema)//找出age80的文档中的第一个文档stuModel.findOne({grades:{$gt:80}},(err,doc) {if(!err){console.log(doc)}})//{ _id: 6017befb5c36d64d08b72577, name: 小芳, grades: 94, __v: 0 }//找出age80的文档中的第一个文档且只输出name字段stuModel.findOne({grades:{$gt:80}},{name:1,_id:0},(err,doc) {if(!err){console.log(doc)}})//{ name: 小芳 }//找出age80的文档中的第一个文档且输出包含name字段在内的最短字段stuModel.findOne({grades:{$gt:80}},{lern:true},(err,doc) {if(!err){console.log(doc)}})//{ _id: 6017befb5c36d64d08b72577 }}
})5.4 复杂查询【$where】
$where 可以使用任意的 JavaScript 作为查询的一部分包含JavaScript 表达式的字符串或者函数案例
var mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,(err) {if(!err){var schema new mongoose.Schema({name:String,grades:Number})//添加一个测试字段// schema.add({test:Number})var stuModel mongoose.model(grades,schema)//添加两条数据// stuModel.create({name:小花,grades:76,test:76},{name:小兰,grades:60,test:30},(err,docs){// console.log(docs)// })//字符串 es5中this与obj指向一样es6中只能用objstuModel.find({$where:this.grades this.test || obj.grades obj.test},(err,doc) {if(!err){console.log(doc)}})//[{_id: 6017d7cb8a95cb2a00aae3ae,name: 小花,grades: 76,test: 76,__v: 0}]//函数stuModel.find({$where:function() {return this.grades this.test || obj.grades obj.test*2}},(err,doc) {if(!err){console.log(doc)}})/*[{_id: 6017d7cb8a95cb2a00aae3ae,name: 小花,grades: 76,test: 76,__v: 0},{_id: 6017d7cb8a95cb2a00aae3af,name: 小兰,grades: 60,test: 30,__v: 0}]*/}
})5.5 常用查询条件
$or 或关系$nor 或关系取反$gt 大于$gte 大于等于$lt 小于$lte 小于等于$ne 不等于$in 在多个值范围内$nin 不在多个值范围内$all 匹配数组中多个值$regex 正则用于模糊查询$size 匹配数组大小$maxDistance 范围查询距离基于LBS$mod 取模运算$near 邻域查询查询附近的位置基于LBS$exists 字段是否存在$elemMatch 匹配内数组内的元素$within 范围查询基于LBS$box 范围查询矩形范围基于LBS$center 范围醒询圆形范围基于LBS$centerSphere 范围查询球形范围基于LBS$slice 查询字段集合中的元素比如从第几个之后第N到第M个元素5.6 特定类型查询
_idnamegrades__vtest6017befb5c36d64d08b72576小明68016017befb5c36d64d08b72577小芳94036017c455ba09d355a49ec8eb小红52056017c455ba09d355a49ec8ec小刚46026017d7cb8a95cb2a00aae3ae小花76046017d7cb8a95cb2a00aae3af小兰6006
方法
方法作用sort排序skip跳过limit限制select显示字段exect执行count计数distinct去重 exec(和 then() 两者返回的都是 promise对象 exec一般用于独立的动作一次性执行 then则用于连续性的动作 从其方法名也可以区别它们的用法exec就是执行的意思then就是然后怎么怎么 exec和then的参数是有所不同的前者是 callback(err,doc)后者则是 resolved(doc),rejected(err) 案例
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})
var stuModel mongoose.model(grades, Schema);// 按test从小到大排序
// 1是升序-1是降序
stuModel.find().sort({test:1}).exec((err,docs){console.log(docs)
})
// 按test从大到小排列
stuModel.find().sort(-test).exec((err,docs){console.log(docs)
})
// 跳过1个显示其他
stuModel.find().skip(1).exec((err,docs){console.log(docs)
})
// 显示2个
stuModel.find().limit(2).exec((err,docs){console.log(docs)
})
// 显示name、grades字段不显示id字段
stuModel.find().select(name grades -id).exec((err,docs){console.log(docs)
})
// 跳过第1个后只显示2个数据按照grades由大到小排序且不显示id字段
stuModel.find().skip(1).limit(2).sort(-grades).select(-id).exec((err,docs){console.log(docs)/[{ name: 小明, grades: 78, v: 0, test: 1 },{ name: 小花, grades: 76, test: 4, v: 0 }]/
})
// 显示集合stuModel中的文档数量
stuModel.find().count((err,count){console.log(count)//6
})
// 返回集合stuModel中的grades的值
stuModel.find().distinct(grades,(err,distinct){console.log(distinct)//[ 46, 52, 60, 76, 78, 94 ]
})6.文档更新 6.1 update()
Model.update(conditions, doc, [options], [callback])参数 conditions查询条件doc需要修改的数据插入的数据[options]控制选项 safe (boolean) 默认为true。安全模式。 upsert (boolean) 默认为false。如果不存在则创建新记录。 multi (boolean) 默认为false。是否更新多个查询记录。 runValidators 如果值为true执行Validation验证。 setDefaultsOnInsert 如果upsert选项为true在新建时插入文档定义的默认值。 strict (boolean) 以strict模式进行更新。 overwrite (boolean) 默认为false。禁用update-only模式允许覆盖记录。 [callback]回调函数若设置了查询条件当数据库不满足时默认什么也不发生update() 方法中的回调函数不能省略否则数据不会更新当回调无有用信息时可以使用exec()简化
stuModel.update({name:小明},{$set:{test:34}}.exec())案例
//第一步引入mongoose
const mongoose require(mongoose)
//第二步连接数据库
mongoose.connect(mongodb://localhost:27017/student,err{if(!err){//第三步创建模板var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})// var Schema new Schema()//第四步将模板映射到集合并创建var stuModel mongoose.model(grades,Schema)//查询name为小明的数据并将其test更改为34//若有多个文档默认只更新第一个stuModel.update({name:小明},{$set:{test:34}},(err,raw){console.log(raw)})//{ n: 1, nModified: 1, ok: 1 }//6017befb5c36d64d08b72576 小明 68 0 34}
})6.2 updateOne()
Model.updateOne(conditions, doc, [options], [callback])与update()相似唯一区别为updateOne() 默认更新一个文档即使设置{multi:true}也无法只更新一个文档
6.3 updateMany()
Model.updateMany(conditions, doc, [options], [callback])与update()相似唯一区别为updateMany() 默认更新多个文档即使设置{multi:false}也无法只更新一个文档
6.4 find()save()
用于复杂更新
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,err{if(!err){var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})var stuModel mongoose.model(grades,Schema)//查询成绩小于60的数据并在其名字后添加‘差生’字段stuModel.find({grades:{$lt:60}},(err,docs){console.log(docs);/*[{test: 0,_id: 6017c455ba09d355a49ec8eb,name: 小红,grades: 52,__v: 0},{test: 0,_id: 6017c455ba09d355a49ec8ec,name: 小刚,grades: 46,__v: 0}]*/docs.forEach((item,index,arr) {item.name 差生//将修改后的数据保存item.save()})console.log(docs)/*[{test: 0,_id: 6017c455ba09d355a49ec8eb,name: 小红差生,grades: 52,__v: 0},{test: 0,_id: 6017c455ba09d355a49ec8ec,name: 小刚差生,grades: 46,__v: 0}]*/})}
})6.5 findOne() save()
用于复杂更新findOne()返回值为文档对象
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,err{if(!err){var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})var stuModel mongoose.model(grades,Schema)//查询成绩小于60的数据并在其名字后添加‘差生’字段stuModel.findOne({name:小明},(err,doc){console.log(doc);//{test: 34,_id: 6017c455ba09d355a49ec8eb,name: 小明,grades: 68,__v: 0},doc.age 10doc.save()console.log(docs)//{test: 34,_id: 6017c455ba09d355a49ec8eb,name: 小明,grades: 78,__v: 0}})}
})6.6 fingOneAndUpdate()
Model.findOneAndUpdate([conditions], [update], [options], [callback])
6.7 findByIdAndUpdate()
Model.findByIdAndUpdate([conditions], [update], [options], [callback])
7.文档删除 7.1 deleteOne()
会删除符合条件的所有数据Model的deleteOne
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,err{if(!err){var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})var stuModel mongoose.model(grades,Schema)//删除名字中包含‘差生’的数据stuModel.deleteOne({name:/差生/},function(err){})// 回调函数不能省略但可以使用exec() 简写//stuModel.deleteOne({name:/差生/}).exec()})}
})文档的deleteOne
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student,err{if(!err){var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})var stuModel mongoose.model(grades,Schema)//删除名字中包含‘差生’的数据stuModel.find({name:/差生/},function(err,docs){docs.forEach((item,index,arr){item.deleteOne((err,doc){//doc为被删除的值console.log(doc)})})})})}
})7.2 findOneAndRemove()
删除符合条件的一条数据Model.findOneAndRemove(conditions, [options], [callback])回调不可省略但可以使用exec() 简写
stuModel.findOneAndRemove({name:/差生/}).exec()7.3 findByIdAndRemove()
通过id删除数据id是唯一的Model.findByIdAndRemove(conditions, [options], [callback])回调不可省略但可以使用exec() 简写
8.前后钩子 前后钩子即 pre() 和 post() 方法中间件中间件在schema上指定类似静态方法或实例方法等可以在执行以下操作时设置前后钩子 init validate save remove count find findOne findOneAndRemove findOneAndUpdate insertMany update 【pre()】在执行某些操作前执行 【post】在执行某些操作前后执行不可以使用next()
案例
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({ name:String,grades:Number,test:{type:Number,default:0}})
Schema.pre(find,function(next){console.log(我是pre方法1);next();
});
Schema.pre(find,function(next){console.log(我是pre方法2);next();
});
Schema.post(find,function(docs){console.log(我是post方法1);
});
Schema.post(find,function(docs){console.log(我是post方法2);
});
var stuModel mongoose.model(grades, Schema);
stuModel.find(function(err,docs){console.log(docs[0]);
})
/*
我是pre方法1
我是pre方法2
我是post方法1
我是post方法2
{test: 34, _id: 6017befb5c36d64d08b72576,name: 小明,grades: 78,__v: 0}
*/9.文档验证 保证保存文档时可以按照Schema设置的字段进行设置
9.1 【required】数据必填
//将name设置为必填字段如果没有name字段文档将不被保存且出现错误提示
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:{type:String,required:true},age:Number
})
var stuModel mongoose.model(students, Schema);
new stuModel({age:20}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})//报错name: Path name is required.9.2 【default】默认值
//设置age字段的默认值为18如果不设置age字段则会取默认值
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:String,age:{type:Number,default:18}
})
var stuModel mongoose.model(students, Schema);
new stuModel({name:李雷}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})//{ age: 18, _id: 6018f3bd7e51343e6c4f212b, name: 李雷, __v: 0 }9.3 【min】【max】最小/大值
只适用于数字
//将age的取值范围设置为[0,10]。如果age取值为20文档将不被保存且出现错误提示
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:String,age:{type:Number,min:10,max:18}
})
var stuModel mongoose.model(students, Schema);
new stuModel({name:李雷,age:20}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})//age: Path age (20) is more than maximum allowed value (18).9.4 【match】正则匹配
只适用于字符串
//将name的match设置为必须存在01字符。如果name不存在01文档将不被保存且出现错误提示
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:{type:String,match:/01/},age:Number,
})
var stuModel mongoose.model(students, Schema);
new stuModel({name:李雷,age:20}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})//name: Path name is invalid (李雷).9.5【enum】枚举匹配
只适用于字符串
//将name的枚举取值设置为[zs,ls,ww]如果name不在枚举范围内取值文档将不被保存且出现错误提示
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:{type:String,enum:[zs,ls,ww]},age:Number,
})
var stuModel mongoose.model(students, Schema);
new stuModel({name:lss,age:20}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})//name: ValidatorError: lss is not a valid enum value for path name.9.6 【validate】自定义匹配
validate实际上是一个函数函数的参数代表当前字段返回true表示通过验证返回false表示未通过验证
//定义名字name的长度必须在4个字符以上
const mongoose require(mongoose)
mongoose.connect(mongodb://localhost:27017/student)
var Schema new mongoose.Schema({name:{type:String,validate:nameLength},age:Number,
})
var stuModel mongoose.model(students, Schema);
new stuModel({name:abcd,age:20}).save((err,doc){if(err){return console.log(err)}console.log(doc)
})function nameLength(arg){if(arg.length4){return true}return false
}//name: Validator failed for path name with value abcd