初入MongoDB
業(yè)務(wù)需求,需要用到MongoDB雄妥。向來一直是mysql數(shù)據(jù)庫的思想最蕾,一下轉(zhuǎn)換為nosql還是很不適應(yīng)。經(jīng)過一個(gè)月的開發(fā)老厌,寫一下自己的感觸瘟则。本文會(huì)對(duì)應(yīng)mysql數(shù)據(jù)庫進(jìn)行說明。
數(shù)據(jù)庫類型
文檔型數(shù)據(jù)庫:存儲(chǔ)的數(shù)據(jù)是非結(jié)構(gòu)化數(shù)據(jù)枝秤。文檔存儲(chǔ)一般用類似 json 的格式存儲(chǔ)醋拧,存儲(chǔ)的內(nèi)容是文檔型的。
相比mysql來說,mysql的表是高度結(jié)構(gòu)化的丹壕,若添加字段可能需要修改表結(jié)構(gòu)庆械。MongoDB的話沒有這個(gè)煩惱,在其中的每條數(shù)據(jù)可以認(rèn)為一個(gè)“文檔”雀费。比如干奢,一篇文章+評(píng)論,它可以存儲(chǔ)為一個(gè)json盏袄,囊括了所有的信息忿峻,直接存入數(shù)據(jù)庫。并且可以動(dòng)態(tài)的橫向擴(kuò)展辕羽,不用擔(dān)心字段不存在的問題逛尚。
結(jié)構(gòu)對(duì)比
關(guān)系型數(shù)據(jù)庫術(shù)語/概念 | MongoDB 術(shù)語/概念 | 解釋/說明 |
---|---|---|
Database | Database | 數(shù)據(jù)庫 |
Table | Collection | 數(shù)據(jù)庫表/集合 |
Row | Document | 數(shù)據(jù)記錄行/文檔 |
Column | Field | 數(shù)據(jù)列/數(shù)據(jù)字段 |
Index | Index | 索引 |
Table joins | 表關(guān)聯(lián)/MongoDB 不支持(可以使用聚合查詢) | |
Primary Key | Object ID | 主鍵/MongoDB 自動(dòng)將_id 設(shè)置為 主鍵 |
接下來介紹一下項(xiàng)目中遇到的查詢,以nodejs為例
使用 & 高級(jí)查詢
基本查詢
//分頁排序參數(shù)
let opt = {
sort: {username: 1},
skip: (value.pageNum - 1) * value.pageSize,
limit: value.pageSize,
}
//條件
let query = {status: {$ne: -1}}
if (params.keyWords) {
//正則表達(dá)式
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();
}
//數(shù)量查詢
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);
}
關(guān)聯(lián)查詢
有時(shí)候由于業(yè)務(wù)的需要刁愿,需要關(guān)聯(lián)查詢绰寞。例如,查詢某部門的信息铣口,需要帶有相應(yīng)的負(fù)責(zé)人滤钱。
這里呢,需要在dept(部門表)中添加相應(yīng)用戶表(user)表的objectId脑题,就是MongoDB生成的_id
const Schema = Model.SchemaExt({
// userId為字段名稱件缸,ref中的“user” 代辦表名
userId: {type: ObjectId, ref: "user"}, // 負(fù)責(zé)人
code: {type: String, required: true, unique: true}, // 部門編號(hào)
name: {type: String, required: true}, // 部門名稱
//...
})
這樣的話,我們可以使用聚合查詢查詢出相關(guān)數(shù)據(jù)
//這里的populate叔遂,代表的是字段名稱
getByIdPopulate(id, populate) {
return this.model.findOne({_id: id}).populate(populate).exec();
}
查詢結(jié)果
{
code: 001
name: 山東分部
userId: {
_id: xxxxx,
username: xx他炊,
phone: xxx
}
}
聚合查詢
這樣引申出另外一個(gè)問題,如果我需要根據(jù)手機(jī)號(hào)查找部門呢
let listedModel = await deptModel.aggregate([
//關(guān)聯(lián)表已艰,form需要關(guān)聯(lián)的表痊末,localField自己的字段,foreignField關(guān)聯(lián)到表的字段凿叠,as關(guān)聯(lián)出的內(nèi)容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}
},
}]
}
}
])