一.简介

介绍

  • Mongoose 是一个让我们可以通过Node来操作MongoDB数据库的一个模块

  • Mongoose 是一个对象文档模型(ODM)库,它是对Node原生的MongoDB模块进行了进一步的优化封装

  • 大多数情况下,他被用来把结构化的模式应用到一个MongoDB集合,并提供了验证和类型装换等好处

  • 基于MongoDB驱动,通过关系型数据库的思想来实现非关系型数据库

优势/好处

  • 为文档创建模式结构(Schema),也可以说是约束

  • 对模型中的对象/文档进行验证

  • 数据可以通过类型装换装换为对象模型

  • 可以使用中间件来应用业务逻辑挂钩

  • 相比MongoDB驱动更容易

new Object

Schema(模式对象)

——Schema 对象定义约束了数据库中的文档结构

Model

——Model 对象作为集合中的所有文档的表示,相当于MongoDB中的collection,它的每一个实例就是一个document文档

Document

——Document表示集合中的具体文档,相当于collection中的一个具体文档

关系:Schema生成Model,Model创造Document

模式(Schemas)

  • 每个 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() 才能查询)

二.安装使用mongoose

前提:安装MongoDB,Nodejs

1.下载安装Mongoose

 npm i mongoose

2.项目中引入mongoose

var mongoose = require(‘mongoose’)

3.连接数据库

mongoose.connect(‘mongodb://数据库ip地址 : 端口号( 默认端口27017可以省略 )/数据库名’)

数据库连接成功事件

补充
将成功回调的on改成once
事件回调函数只执行一次
mongoose.connection.once(‘open’ , () => {})

数据库断开事件

mongoose.connection.once(‘close’ , () => {})

4.创建Schema(模式)对象

var stuSchema = new Schema({})

  • 通过Schema创建Model

  • Model 代表的是数据库中的集合,通过Model才能对数据库进行操作

5.映射

var stuModel = mongoose.model(‘student’,stuSchema)

参数

  1. 要映射的集合名

  2. 创建的约束(Schema对象)

6.通过映射返回的值对数据库进行增、删、改、查

7.断开数据库连接(一般不使用)

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)
集合名称,结构对象

文档新增

create()
  • 操作模型

  • 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 }
            }
        })
 

save()
  • 操作的是文档

  • 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 }
            }
        })

insertMany()
  • 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 }]*/
            }
        })

文档查询

find()
  • Model.find(conditions, [projection], [options], [callback])

  • 参数

    conditions:查询条件

    [projection]:控制返回字段

    [options]:配置查询参数

    [callback]:回调函数–function(err,docs){}

   // 数据查询
        // BookModel.find((err, docs) => {
        //     if (!err) {
        //         console.log(docs)
        //     }
        // })

findById()

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值就可以了,返回单个文档

findOne()
  • 返回查询到的数据的第一个

 // 返回查询到的数据的第一个
        BookModel.findOne({price:{$gt:10}},(err,doc) => {
            if(!err){
                 console.log(doc)
             }
         })

复杂查询【$where】
  • $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 ]
})

文档更新

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({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);
        })

updateOne()
  • Model.updateOne(conditions, doc, [options], [callback])

  • 与update()相似,唯一区别为updateOne() 默认更新一个文档,即使设置{multi:true}也无法只更新一个文档

updateMany()
  • Model.updateMany(conditions, doc, [options], [callback])

  • 与update()相似,唯一区别为updateMany() 默认更新多个文档,即使设置{multi:false}也无法只更新一个文档

find()+save()】 【findOne() + 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}]*/
    })
  }
})
 

文档删除

【remove()】
  • 会删除符合条件的所有数据

// 数据删除
BookModel.remove({name:/西游记/},function(err){})

【findOneAndRemove()】
  • 删除符合条件的一条数据

  • Model.findOneAndRemove(conditions, [options], [callback])

  • 回调不可省略,但可以使用exec() 简写

stuModel.findOneAndRemove({name:/差生/}).exec()

【findByIdAndRemove()】
  • 通过id删除数据(id是唯一的)

  • Model.findByIdAndRemove(conditions, [options], [callback])

  • 回调不可省略,但可以使用exec() 简写

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐