初入MongoDB
阅读原文时间:2023年07月08日阅读:4

业务需求,需要用到MongoDB。向来一直是mysql数据库的思想,一下转换为nosql还是很不适应。经过一个月的开发,写一下自己的感触。本文会对应mysql数据库进行说明。

文档型数据库:存储的数据是非结构化数据。文档存储一般用类似 json 的格式存储,存储的内容是文档型的。

相比mysql来说,mysql的表是高度结构化的,若添加字段可能需要修改表结构。MongoDB的话没有这个烦恼,在其中的每条数据可以认为一个“文档”。比如,一篇文章+评论,它可以存储为一个json,囊括了所有的信息,直接存入数据库。并且可以动态的横向扩展,不用担心字段不存在的问题。

关系型数据库术语/概念

MongoDB 术语/概念

解释/说明

Database

Database

数据库

Table

Collection

数据库表/集合

Row

Document

数据记录行/文档

Column

Field

数据列/数据字段

Index

Index

索引

Table joins

表关联/MongoDB 不支持(可以使用聚合查询)

Primary Key

Object ID

主键/MongoDB 自动将_id 设置为 主键


接下来介绍一下项目中遇到的查询,以nodejs为例

基本查询

//分页排序参数
let opt = {
    sort: {username: 1},
    skip: (value.pageNum - 1) * value.pageSize,
    limit: value.pageSize,
}
//条件
let query = {status: {$ne: -1}}
if (params.keyWords) {
    //正则表达式
    let reg = new RegExp(value.keyWords)
    query['$or'] = [
        {nickname: reg},
        {phone: reg},
    ]
}
let admins = await AdminModel.getByQuery(query, '', opt)
let admin = await AdminModel.getOneByQuery(query)

查询方法

//查询多条
getByQuery(query, fileds, opt) {
    return this.model.find(query, fileds, opt).exec();
}
//查询单条
getOneByQuery(query, fileds, opt) {
    return this.model.findOne(query, fileds, opt).exec();
}
//数量查询
countByQuery(query) {
    return this.model.countDocuments(query)
}
//更新
update(conditions, update, options) {
    return this.model.updateMany(conditions, update, options);
}
//去重查询
distinct(query, field) {
    return this.model.find(query).distinct(field);
}
//保存
save(model) {
    model = model instanceof this.model ? model : new this.model(model);
    return model.save();
}
//更新
update(conditions, update, options) {
    return this.model.updateMany(conditions, update, options);
}

关联查询

有时候由于业务的需要,需要关联查询。例如,查询某部门的信息,需要带有相应的负责人。

这里呢,需要在dept(部门表)中添加相应用户表(user)表的objectId,就是MongoDB生成的_id

const Schema = Model.SchemaExt({
    // userId为字段名称,ref中的“user” 代办表名
    userId: {type: ObjectId, ref: "user"},     // 负责人
    code: {type: String, required: true, unique: true},  // 部门编号
    name: {type: String, required: true},                 // 部门名称
    //...
})

这样的话,我们可以使用聚合查询查询出相关数据

//这里的populate,代表的是字段名称
getByIdPopulate(id, populate) {
    return this.model.findOne({_id: id}).populate(populate).exec();
}

查询结果

{
    code: 001
    name: 山东分部
    userId: {
        _id: xxxxx,
        username: xx,
        phone: xxx
    }
}

聚合查询

这样引申出另外一个问题,如果我需要根据手机号查找部门呢

let listedModel = await deptModel.aggregate([
    //关联表,form需要关联的表,localField自己的字段,foreignField关联到表的字段,as关联出的内容key
    {
        $lookup: {
            from: "admins",
            localField: "admin",
            foreignField: "_id",
            as: "adminDetail"
        }
    }, {
        $unwind: '$adminDetail'
    }, {
        //查询条件,这里query = {'adminDetail.phone': xxx}
        $match: query,
    }, {
        //分页
        $facet: {
            data: [{
                $sort: opt.sort
            }, {
                $skip: opt.skip
            }, {
                $limit: opt.limit
            }],
            count: [{
                $group: {
                    _id: "count",
                    total: {$sum: 1}
                },
            }]
        }
    }
])