Mongoose 是一个让我们可以通过Node来操作MongoDB数据库的一个模块
Mongoose 是一个对象文档模型(ODM)库,它是对Node原生的MongoDB模块进行了进一步的优化封装
大多数情况下,他被用来把结构化的模式应用到一个MongoDB集合,并提供了验证和类型装换等好处
基于MongoDB驱动,通过关系型数据库的思想来实现非关系型数据库
为文档创建模式结构(Schema),也可以说是约束
对模型中的对象/文档进行验证
数据可以通过类型装换装换为对象模型
可以使用中间件来应用业务逻辑挂钩
相比MongoDB驱动更容易
Schema(模式对象)
——Schema 对象定义约束了数据库中的文档结构
Model
——Model 对象作为集合中的所有文档的表示,相当于MongoDB中的collection,它的每一个实例就是一个document文档
Document
——Document表示集合中的具体文档,相当于collection中的一个具体文档
关系:Schema生成Model,Model创造Document
每个 schema 都会映射到一个 MongoDB collection 并定义这个collection里的文档结构
创建一个 schema 对象
const mongoose = require('mongoose')
//调用 Schema
const Scheme = mongoose.Schema//创建 schema 对象
var stuSchema = new Schema({
? ? name: String,
? ? age: Number,
? ? gender:{
? ? ? ? type: String,
? ? ? ? default:'male' //定义默认类型
? ? },
? ? addr: String
})
在Schema定以后添加字段时需要使用 add() 方法
var stuSchema = new Schema({
? ? {...},
? ? { timestamps:true }
})
【_id】
当未定义_id
字段时 mongoose 会为每一个文档自动添加一个不重复的_id
,类型为ObiectId(在查询语句中需要通过 findById() 才能查询)
前提:安装MongoDB,Nodejs
?npm i mongoose
var mongoose = require(‘mongoose’)
mongoose.connect(‘mongodb://数据库ip地址 : 端口号( 默认端口27017可以省略 )/数据库名’)
补充
将成功回调的on改成once
事件回调函数只执行一次
mongoose.connection.once(‘open’ , () => {})
mongoose.connection.once(‘close’ , () => {})
var stuSchema = new Schema({})
通过Schema
创建Model
Model 代表的是数据库中的集合,通过Model才能对数据库进行操作
var stuModel = mongoose.model(‘student’,stuSchema)
参数
要映射的集合名
创建的约束(Schema对象)
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/user');// 设置连接成功的回调
mongoose.connection.once('open', () => {
? ? if (mongoose.connection.readyState === 1) {
? ? console.log("连接成功");? ? // 创建文档的结构对象
? ? let BookSchema = new mongoose.Schema({
? ? ? ? name: {
? ? ? ? ? ? type: String,
? ? ? ? ? ? required: true
? ? ? ? },
? ? ? ? author: String,
? ? ? ? price: Number
? ? });? ? // 创建模型对象
? ? let BookModel = mongoose.model('books', BookSchema);? ? // 数据插入
? ? BookModel.create(
? ? ? ? {
? ? ? ? ? ? name: '西游记',
? ? ? ? ? ? author: '哈哈',
? ? ? ? ? ? price: 19.9,
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? name: '红楼梦',
? ? ? ? ? ? author: '曹雪芹',
? ? ? ? ? ? price: 19.9,
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? name: '水浒传',
? ? ? ? ? ? author: '111',
? ? ? ? ? ? price: 19.9,
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? name: '三国演义',
? ? ? ? ? ? author: '2222',
? ? ? ? ? ? price: 19.9,
? ? ? ? },
? ? ? ? (err, data) => {
? ? ? ? ? ? if (err) {
? ? ? ? ? ? ? ? console.log(err);
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? console.log(data);
? ? ? ? ? ? // 插入数据后关闭连接
? ? ? ? ? ? mongoose.disconnect();
? ? ? ? }
? ? );
? ? // 数据删除
? ? // ? BookModel.remove({name:/西游记/},function(err){})
}
});// 设置连接错误的回调
mongoose.connection.on('error', () => {
? ? console.log("连接失败");
});// 设置连接关闭的回调
mongoose.connection.on('close', () => {
? ? console.log("连接关闭");
});
?
创建文档的结构对象
设置集合中文档的属性以及属性值的类型
Let BookSchema= new mongoose.Schema({
name: String
author: String;
price:Number
})
创建模型对象 对稳定操作的封装对象
Let BookModel= mongoose.model( ' books ',BookSchema)
集合名称,结构对象
操作模型
Model.create(doc(s), [callback])
参数:
[doc(s)]:文档对象或文档对象数组
[callback]:回调函数
?// 数据插入
? stuModel.create({name:"小明",grades:68},{name:"小红",grades:80},(err,doc1,doc2) => {
? ? ? ? ? ?if(!err){
? ? ? ? ? ? ?? ?console.log(doc1)
? ? ? ? ? ? ?? ?//{ _id: 6017be2d77c8dd01242624bb, name: '小明', grades: 68, __v: 0 }
? ? ? ? ? ? ?? ?console.log(doc2)
?? ??? ??? ??? ?//{ _id: 6017be2d77c8dd01242624bc, name: '小红', grades: 80, __v: 0 }
? ? ? ? ?? ?}
? ? ? ? })
?
操作的是文档
Model.prototype.save([options], [options.safe], [options.validateBeforeSave], [fn])
?//链式调用 通过new 一个Model创建一个 document
? ? ? ? new stuModel({name:"小明",grades:68}).save((err,docs) => {
? ? ? ? ? ? if(!err){
? ? ? ? ? ? ? ? console.log(docs)
? ? ? ? ? ? ? ? //{ _id: 6017bd1cf4cc8544d8ed2a8a, name: '小明', grades: 68, __v: 0 }
? ? ? ? ? ? }
? ? ? ? })
Model.insertMany(doc(s), [options], [callback])
返回值为一个数组
?//链式调用 通过new 一个Model创建一个 document
? ? ? ? stuModel.insertMany({name:"小明",grades:68},{name:"小芳",grades:94},(err,docs) => {
? ? ? ? ? ?if(!err){
? ? ? ? ? ? ?? ?console.log(docs)
? ? ? ? ? ? ?? ?/*[{ _id: 6017befb5c36d64d08b72576, name: '小明', grades: 68, __v: 0 },
? ? ? ? ? ? ? ? ? ?{ _id: 6017befb5c36d64d08b72577, name: '小芳', grades: 94, __v: 0 }]*/
? ? ? ? ?? ?}
? ? ? ? })
Model.find(conditions, [projection], [options], [callback])
参数
conditions:查询条件
[projection]:控制返回字段
[options]:配置查询参数
[callback]:回调函数–function(err,docs){}
? ?// 数据查询
? ? ? ? // BookModel.find((err, docs) => {
? ? ? ? // ? ? if (!err) {
? ? ? ? // ? ? ? ? console.log(docs)
? ? ? ? // ? ? }
? ? ? ? // })
Model.findById(conditions, [fields], [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)
? ? ? ? //保存查询数据的_id
? ? ? ? var 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 }
? ? ? ? ?? ?}
? ? ? ? })
? ? }
})
注:conditions写一个id值就可以了,返回单个文档
返回查询到的数据的第一个
?// 返回查询到的数据的第一个
? ? ? ? BookModel.findOne({price:{$gt:10}},(err,doc) => {
? ? ? ? ? ? if(!err){
? ? ? ? ? ? ? ? ?console.log(doc)
? ? ? ? ? ? ?}
? ? ? ? ?})
$where 可以使用任意的 JavaScript 作为查询的一部分,包含JavaScript 表达式的字符串或者函数
?// 字符串 es5中this与obj指向一样,es6中只能用obj
? ? ? ? BookModel.find({$where:"this.name == this.author" || "obj.name == obj.author"},(err,doc) => {
? ? ? ? ? ? if(!err){
? ? ? ? ? ? ? ? ?console.log(doc)
? ? ? ? ? ? ?}
? ? ? ? ?})
? ? ? ? ?//函数
? ? ? ? ?BookModel.find({$where:function() {
? ? ? ? ? ? return this.name == this.author || obj.name == obj.author
? ? ? ? }},(err,doc) => {
? ? ? ? ? ? if(!err){
? ? ? ? ? ? ? ? ?console.log(doc)
? ? ? ? ? ? ?}
? ? ? ? ?})
stuModel.find({grades:{$gt:90}},(err,docs)=>{
? ? console.log(docs);
})
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从小到大排序
stuModel.find().sort('test').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 ]
})
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({grades:{$gt:80}},{test:40},function(err,raw){
? ? //{ n: 1, nModified: 1, ok: 1 }
? ? console.log(raw);
})
如果要同时更新多个记录,需要设置options里的multi为true。
?temp.update({name:/a/},{age: 10},{multi:true},function(err,raw){
? ? ? ? ? ? //{ n: 2, nModified: 2, ok: 1 }
? ? ? ? ? ? console.log(raw);
? ? ? ? })
Model.updateOne(conditions, doc, [options], [callback])
与update()相似,唯一区别为updateOne() 默认更新一个文档,即使设置{multi:true}也无法只更新一个文档
Model.updateMany(conditions, doc, [options], [callback])
与update()相似,唯一区别为updateMany() 默认更新多个文档,即使设置{multi:false}也无法只更新一个文档
用于复杂更新
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}]*/
? ? })
? }
})
?
会删除符合条件的所有数据
// 数据删除
BookModel.remove({name:/西游记/},function(err){})
删除符合条件的一条数据
Model.findOneAndRemove(conditions, [options], [callback])
回调不可省略,但可以使用exec() 简写
stuModel.findOneAndRemove({name:/差生/}).exec()
通过id删除数据(id是唯一的)
Model.findByIdAndRemove(conditions, [options], [callback])
回调不可省略,但可以使用exec() 简写