1. 程式人生 > 實用技巧 >初入MongoDB

初入MongoDB

初入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}
                },
            }]
        }
    }
])