Mongoose 从入门到精通

mongoose 简介:

mongoose: elegant mongoldb object modeling for node.js

官网是这样解释mongoose。伟哥在 NodeJS 对 MongoDB 封装的文章中虽然对 mongoldb 进行封装后简化了使用,但是对于编写 MongoDB 验证,转换和业务逻辑还是比较复杂的。对于之前使用 Java 习惯封装 DAO 层来后端程序员来,这样编写来操作数据库也是非常不方便。Mongoose 为模型提供了一种直接,基于scheme结构去定义你的数据模型。它内置数据验证,查询构建,业务逻辑钩子等,开箱即用。

开始使用

快速上手 官方的指导先放在这。

大家浏览完官方文档的快速上手之后,使用 mongoose 可以大致分为一下几个步骤:

  1. 引入 mongoose 模块

  2. 连接 mongodb 数据库

  3. 创建 schema

  4. 创建 model 与数据库中集合(表)建立联系

  5. 增加数据

    • model 实例化
    • 实例.save()
  6. 修改数据 model.updateOne()

  7. 删除数据 model.deleteOne()

  8. 查询数据 model.find()

mongodb 存储的是一个json对象,这个schema可以理解成这个对象构造函数,这个schema的写法写过 Vue 和 React 的小伙伴都应该非常熟悉,这个跟 component 的 props 是一样的,前面是属性名称,后面是该属性值的类型。写过TypeScript的这个写法就更熟悉了。当然它也可以指定默认值,这样一看它就跟 Vue和React中 component 中的 props 完全一样了。 schema 一定要与你将来创建model时映射数据中集合的属性对应起来,否则会造成插入或修改失败。

代码实例

/* 引入 mongoose 模块 */
const mongoose = require('mongoose');
/* 与数据库连接 第二参数还是传入,否则会报出一个警告,看着别扭*/
mongoose.connect('mongodb://127.0.0.1:27017/test',{ useNewUrlParser: true });
/* 创建 schema  */
const NewsSchema = mongoose.Schema({
  title: String,
  author: String,
  content: String,
  status: {
    type: Number,
    default:1
  }
});
/* 创建 model 与 数据库建立联系 */
/* 第一个参数 model 名称,首字母最好大写
 * 第二个参数 scheme 
 * 第三个参数就是与数据库那个collection建立联系
*/
const News = mongoose.model('News', NewsSchema,'news');
/* 增加数据 在news表中增加一条数据*/
/* 创建一个实例 */
const news = new News({title:'News Title',author:'author', content:'News Content', status:1});
/* 调用实例save方法进行数据保存,即使数据库中没有news 这张表,它会先创建表在插入数据*/
news.save(callback)
/* 修改数据 修改status*/
News.updateOne({title:'News Title'},{status:2},callback);
/*删除数据*/
News.deleteOne({title:'News Title'},callback);
/* 查询数据 */
News.find(callback) 或者 News.find({title:/^News/},callback)

mongoose 模块化

通过上一节的了解 使用mongoose操作数据已经可以,但是到我们需要对某一个collection(表)进行操作时我们总不能先吧上面的定义一通,所有我们需要对其进行模块化。封装的时候就跟 Java 中封装的 DAO层一样,不过在这里我们还是叫 model 比较切合 mongoose 中的概念。

mongoose的封装我们分为 2 步走:

  1. 封装一下如何获取 mongodb 的实例,
  2. 讲我们用到数据表的 model 都放在 model 文件夹中(当然了这个名字随意)

代码示例:

/* 封装 db.js 获取链接数据库实例 */
const mongoose = require('mongoose');
/*第一参数是数据库连接*/
/*第二个参数根据官方配置,不然那个数据库弹出警告*/
/*第三个参数 回调函数*/
mongoose.connect('mongodb://127.0.0.1:27017/test',{useNewUrlParser: true},(err)=>{
  if(err) throw err,
  console.log('数据库连接成功')
})
module.exports = mongoose;
/* 封装 modle (Java中的DAO) 以 news 表为例 */
const mongoose = require('./db.js');
const NewsSchema = mongoose.Schema({
        title:String,
    author:String,
    content:String,
    status:Number
})
module.exports = mongoose.model('News', NewsSchema, 'news');
/* 使用 */
const NewsModel = require('./model/news.js');

NewsModel.find({},(err,doc)=>{
  if(err) throw err;
  console.log(doc);
})

Mongoose 预定义修饰符 Getter 与 Setter

Mongoose 提供的一些预定义修饰符可以帮我们存取数据进行一些格式化的操作。

Mongoose 本身提供了一些预定义的修饰符,设置这些属性在数据存入数据库的时候就会有对应的操作。

// mongoose 预定义修饰符
trim:true  //去首尾空格
lowercase:true //转化为小写
uppercase:true  //转化为大写

var UserSchema=mongoose.Schema({
  name:{
    type:String,
    trim:true  //去首尾空格
  },
  age:Number,
  status:{
    type:Number,
    default:1,
        lowercase:true 
  }
})

Mongoose 也提供了自定义修饰符 Setter 和 Getter,Setter 会在数据存入数据库时进行格式化操作,Getter只是在输出实例的时候会进行定义的操作,读数据库的数据没有任何影响(没什么用)。

上代码:

// 加入我们要对 url 进行格式化,如果数据以 http:// 开头我们原样存入,如果不以 http:// 开头,添加之后再存入数据库

const ArticleSchema = mongoose.Schema({
    title:String,
    author:String,
    img:{
        type:String,
        set(params){
            if(!params) return params;
            return /^http:\/\//.test(params) ? params : 'http://' + params
        },
        get(params){
            return 'mongodb:' + params;
        }
    }
});

const article2 = new Article({
    title:'武汉加油',
    author: '人民日报',
    img:'wuhan/pic02'
});

// 这样存入数据库的数据就是 http://wuhan/pico2

console.log(article2.img) // mongo:wuhan/pic02 ---- getter就是这样用,所有没啥用处

Mongoose 内置 CURD 方法,扩展 Mongoose Model 的静态方法和实例方法

// 内置 CURD 方法

model.deleteMany()
model.deleteOne()
model.find()
model.findById()
model.findByIdAndDelete(),
model.findByIdAndRemove(),
model.findByIdAndUpdate(),
model.findOneAndDelete(),
model.findOneAndRemove(),
model.findOndAndUpdate(),
model.replaceOne(),
model.updateMany(),
model.updateOne()

ArticalModule.updateOne({'title':'武汉加油'},{$set:{'title':'中国加油,武汉加油'}})

在 mongoose 方法基础上进行封装,例如 我们定义一个按照 title 查找的方法

Mongoose 分为静态方法和实例方法两种,这个跟各编程语言的静态和实例方法一个意思

// 静态方法
ArticleSchema.static({
    findByTitle(title,cb){
        this.find({title},function(err,docs){
      cb(err,docs)
    })
    }
})

// 实例方法
ArticleSchema.method({
     console.log('这是一个实例方法');
     console.log(this.name);
})

Mongoose 数据校验

Mongoose 数据校验

mongoose 聚合管道 (连表查询)

聚合管道其实就是mongodb的连表查询

举个例子:现在有两张表,订单表(order)和订单清单表(orderItem)

现在进行查询获取所有订单总价个大于90的订单号订单项清单

Order.aggregate([
    {
        $lookup:{
            from:'orderItem',   // 有集合
            localField: 'id', // 做集合连接键
            foreignFileId: 'order_id', // 有集合外键
            as:'items'  //查询到集合的别名

        },
        $match:{
            'all_price' : {$get:90}}  大于九十
        }
    }

])

// 上面的写成SQL语句就是
// select * from order right join orderItem where order.id = orderItem.order_id and order.all_price > 90  这样理解起来localField 和 foreignField 也许就简单了

上面是两个表 多表查询呢?

//有三张表
//分类表
articlecate: {
    id: Schema.Types.ObjectId,
    title:String,
    description: String,
    add_time: Date
}

//文章表
article:{
    id:Schema.Types.ObjectId,
    cid:Schema.Types.ObjectId,
    title:String,
    description:string,
    author_id:Schema.Types.ObjectId,
    author_name:String,
    content:String,
    add_addtime:Date
}
//用户表
user:{
    id:Schema.Types.ObjectId,
    username:String,
    password:String,
    name:String,
    age:Number,
    sex:String,
    tel:String,
    add_time:Date
}


// 查询文章信息,并显示文章分类,以及作者信息


ArticleModule.aggregate([
    {
        $lookup:{
            from: 'articlecate',
            localField: 'cid',
            foreignField:'id',
            ad:articlecate
        }
    }{
        $lookup:{
            from: 'user',
            localField:'auth_id',
            foreignField:'id',
            as:user
        }

    },{
        $match:{
            id: Schema.Type.ObjectId('123')
        }
    }
],(err,docs)=>{
    console.log(JSON.stringify(docs))
})

管道管道,直接写就OK了。还有一直用写法是用Populate来进行多表查询,但是这种写法性能上不如 $lookup,但是写法上简单的。它的使用必须在创建 schema 时就要创建外键(跟关系性数据快快要一致了),具体用法可以看下面教程,写的简单易懂,主要是作者头像很好看 hhh
详解 mongoose Populate
其他聚合需要了解的内容

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • mongoose入门 MongoDB是一个开源的NoSQL数据库,相比MySQL那样的关系型数据库,它更显得轻巧、...
    huilegezai阅读 4,434评论 0 14
  • 参考深入浅出mongoose 连接mongoose mongoose连接数据库有两种方式第一种: 第二种: mon...
    bacbcc94613b阅读 12,303评论 1 27
  • 原文地址 本文简单的介绍了数据库,以及如何在 Node/Express 中应用他们。之后展示如何使用Mongoos...
    前端幼儿班阅读 5,143评论 1 5
  • 初学Node.js接触到MongoDB数据库,阅读资料中推荐的都是Mongoose模块,可以更加方便的对数据库进行...
    LnEoi阅读 31,400评论 9 49
  • 身处黑暗,心存光明
    wby_70b5阅读 20评论 0 0