时间: 2020-08-25|tag:33次围观|0 条评论

前提

  • 安装Node
  • 新建一个单独的目录安装MongoDB并开启服务
  • 新建项目目录,npm init初始化并安装mongoose包npm i mongoose -S
  • 建议npm i -g supervisor安装supervisor,用于监听当前目录下 node 和 js 后缀的文件,当这些文件发生改动时,supervisor 会自动重启程序。
  • 运行mongo连接数据库

核心

名词解释

  • Schema:以文件形式存储的数据库模型骨架,不具备操作数据库的能力
  • Model:由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
  • Entity:由Model创建的实体,也可以对数据库进行操作

三者关系
Schema 生成 Model,Model 创造 Entity,Model 和 Entity 都可以对数据库进行操作,但 Model 比 Entity 更具操作性


应用

首先要知道,数据库的所有操作都是异步的。

基本操作
  • 增:save()
  • 删:remove()
  • 查:find(),findOne()
  • 改:update(),updateMany()

结合代码使用

# test.jsconst mongoose = require('mongoose')mongoose.Promise = global.Promise// 最好加上这句话const Schema = mongoose.Schemaconst log = console.logconst err = console.error// 创建连接,因为数据库操作是异步的,使用then方法可保证连接之后才执行操作const db = mongoose.connect('mongodb://localhost/test').then(() => {    // Schema和Model变量名大写,entity变量名小写,集合名小写,如cats    const CatSchema = Schema({ name: String }) // Schema    const CatModel = mongoose.model('cats', CatSchema)  //Model    const catEntity = new CatModel({ name: 'Dolb' })  //实体 entity          //以下所有逻辑都在这里进行})
  • 增加一条数据
    // 增    catEntity.save((e,res)=>{        if(e){            err(e)        }else{            log('save suc')        }    })

这里我运行node test.js保存成功后退出程序并再次node test.js

Mongoose 基本操作插图
运行两次node test.js

得到的是几条数据呢?

Mongoose 基本操作插图1
查看数据条目

得到了两条数据,结论是数据库的数据没有覆盖一说,哪怕内容相同,重复save只会重复添加。

为了方便后面的演示,将const catEntity = new CatModel({ name: 'Dolb' })中的name值分别改为MiaoMimi,这样数据库下的cats集合里就有以下四条数据:

Mongoose 基本操作插图2
当前数据

另外补充一下,使用Model来新增数据使用create方法,如:CatModel.create({name: 'Dot'} , callback)

  • 删除一条数据
    因为数据库的操作都是异步的,那么在保存和删除同时存在时我们不能保证代码的执行顺序,所以得到的很可能是我们不愿意看到的结果,假设代码是这个样子的:
    // 增    catEntity.save((e, res) => {        if (e) {            err(e)        } else {            log('save suc')        }    })    // 删除新增的Mimi的数据    catEntity.remove({ name: 'Mimi' }, (e, res) => {        if (e) {            err(e)        } else {            log('remove Mimi suc')        }    })

Mongoose 基本操作插图3
运行node
Mongoose 基本操作插图4
结果

是不是和想象的完全不一样?那么怎样做到删除当前增加的条目呢?

    // 增    catEntity.save((e, res) => {        if (e) {            err(e)        } else {            log('save suc')            // 删除新增的Mimi的数据            catEntity.remove({ name: 'Mimi' }, (e, res) => {                if (e) {                    err(e)                } else {                    log('remove Mimi suc')                }            })        }    })

将删除的代码放进增加的代码中,就可以保证删除在新增之后执行

Mongoose 基本操作插图5
运行node
Mongoose 基本操作插图6
数据

可以看到仍是5条数据,说明新增的Mimi被删除了,事实上remove的第一个参数不写就可以做到删除当前条目了:

    // 增    catEntity.save((e, res) => {        if (e) {            err(e)        } else {            log('save suc')            // 删除新增的Mimi的数据            catEntity.remove((e, res) => {                if (e) {                    err(e)                } else {                    log('remove Mimi suc')                }            })        }    })

Mongoose 基本操作插图6
数据

可是假设现在我们需要删除所有name为Dolb的数据,又该怎么做呢?这个时候就要用到Model了⬇️

  • 删除所有符合条件的数据
    首先我们将前面的代码注释掉,再添加以下代码
    // 删除所有符合name值为Dolb的数据    CatModel.remove({ name: 'Dolb' }, (e, res) => {        if (e) {            err(e)        } else {            log('remove Dolb suc')        }    })
Mongoose 基本操作插图7
数据
  • 删除所有数据
    删除所有数据即去掉remove方法的第一个参数
    CatModel.remove((e, res) => {        if (e) {            err(e)        } else {            log('remove Dolb suc')        }    })

这里为了接下来的操作就不执行这段代码了

  • 查找所有符合条件的数据
    CatModel.find({ name: 'Mimi' }, (e, res) => {        if (e) {            err(e)        } else {            log('find Mimi suc: There have ' + res)        }    })
  • 查找所有数据
    CatModel.find((e, res) => {        if (e) {            err(e)        } else {            log('find all cats suc: There have ' + res)        }    })
Mongoose 基本操作插图8
数据

到这里我误删了所有数据,所以重新新建的数据如下:

Mongoose 基本操作插图9
现在的数据
  • 修改
    CatModel.update({ name: 'Miao' }, { name: 'Miao2' }, (e, res) => {        if (e) {            err(e)        } else {            log('更新成功')            // 只更新一个            CatModel.updateOne({ name: 'Miao2' }, { name: 'Miao3' }, (e, res) => {                if (e) {                    err(e)                } else {                    log('更新第一个Miao成功')                }            })        }    })    CatModel.updateMany({ name: 'Mimi' }, { name: 'Mimi2' }, (e, res) => {        if (err) {            err(err)        } else {            log('更新成功')        }    })
Mongoose 基本操作插图10
加入updateOne前后,数据的变化

所以update和updateMany有什么区别呢?


进阶
  • Middleware中间件,重点:next(),hook钩子。
  • Plugin插件,用来更新Schema的功能,而全局Plugin用于更新全部Schema的功能,所以全局plugin最好放在靠前的位置。
  • Validation验证器,验证存入数据库的数据
const mongoose = require('mongoose')const Schema = mongoose.Schemaconst log = console.logconst err = console.error// Plugin插件,用来更新Schema的功能// 全局Plugin,更新全部Schema的功能,全局plugin最好放在靠前的位置// 以下代码为所有操作打上时间戳function TimePlugin(schema, options) {    const str = 'save time'    schema.pre('save', next => {        console.time(str)        next()    })    schema.post('save', next => {        console.timeEnd(str)    })}mongoose.plugin(TimePlugin)const PostSchema = new Schema({    title: {        type: String,        // Validation  验证器 验证存入数据库的数据        // 验证器,validate是放在Schema下的字段用来做字段限制的        validate: {            validator: v => v.length < 10,            message: '文章标题长度必须小于10'        }    },    author: {        type: Schema.Types.ObjectId,        ref: 'User'    },    rawContent: String,    create_at: {        type: Date,        default: Date.now    },    update_at: {        type: Date,        default: Date.now    },    comments: {        type: Array    },    votes: Number,    downs: Number})const UserSchema = new Schema({    name: String,    sex: Number,    avatar: String,    mail: String,    password: String})const CommentSchema = new Schema({    author: {        type: Schema.Types.ObjectId,        required: true    },    content: {        type: 'string',        required: true    },    postId: {        type: Schema.Types.ObjectId,        required: true    }})const PostModel = mongoose.model('Post', PostSchema)const UserModel = mongoose.model('User', UserSchema)const CommentModel = mongoose.model('Comment', CommentSchema)const db = mongoose.connect('mongodb://localhost/dolb').then(() => {    // 1. 插入文章    function addPost(post) {        const postEntity = new PostModel(post)        postEntity.save((e, result) => {            if (e) {                err(e)            } else {                log('保存成功啦')                //    getPostByTitle('hello world')// 插入之后才能查到文章,而操作都是异步的,不能保证顺序,所以调用getPostByTitle放在addPost里能保证查得到            }        })    }    addPost({        title: 'hello wo'    })    // 2. 根据id删除文章    function removePostById(postId) {        PostModel.remove({ _id: postId }, (e, res) => {            if (e) {                err(e)            } else {                log('删除所有id为...成功啦')            }        })    }    // removePostById('5a609fba3906973fc61f640b')    // 3. 根据文章标题查找文章    function getPostByTitle(title) {        PostModel.find({ title }, (e, res) => {            if (e) {                err(e)            } else {                log(res)            }        })    }    // 4.更新文章    function updatePost(id, title) {        PostModel.update({ _id: id }, { title }, (e, res) => {            if (e) {                err(e)            } else {                log(res)            }        })    }    // updatePost('5a60a17d951bc340519c0e95','hey dolby')})// middleware中间件PostSchema.pre('save', next => {    log('hey i am pre hook')    next()})PostSchema.post('save', next => {    log('hey i am post hook')})

执行现有的代码,得到:

hey i am pre hooksave time: 9.787mshey i am post hook保存成功啦

证明钩子优先级大于自身回调


常见报错

  • *** is not a constructor
    解决办法:
    如:CatSchema is not a constructor。说明调用了new CatSchema来生成实例,但是Schema是不能生成实例的,必须到Model才能生成实例,修改new CatSchemanew CatModel

  • Schema is not defined
    解决办法:
    Schema需要引入,如const Schema = require('mongoose').Schema或者const Schema = mongoose.Schema


实践结论

  • 依赖于其他表时需要用到ObjectId
  • hook钩子(pre,next)优先级大于自身回调
  • populate用于处理关联表

查询Mongoose API

文章转载于:https://www.jianshu.com/p/9d34af40e135

原著是一个有趣的人,若有侵权,请通知删除

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《Mongoose 基本操作
   

还没有人抢沙发呢~