初入MongoDB
业务需求,需要用到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}
},
}]
}
}
])