# 簡介
Mongoose 庫簡而言之就是在 Node.js 環境中操作 MongoDB 數據庫的一種便捷的封裝,一種對象模型工具,Mongoose 將數據庫中的數據轉換為 JavaScript 對象以供你在應用中使用。(即可以通過 JavaScript 代碼在 Node.js 環境下去操作 MongoDB 數據庫)。
# 連接數據庫
* 新建項目目錄 mongoose-demo,打開命令行跳轉這個項目目錄路徑執行以下命令:
~~~
npm init -y
npm install mongoose
~~~
* 編寫 01.db.js,文件位置 mongoose-demo/01.db.js,內容如下:
~~~
const mongoose = require('mongoose');
const DB_URL = 'mongodb://localhost/test';
?
// 連接
mongoose.connect(DB_URL);
?
// 給事件 connected 綁定處理函數,當連接成功時執行
mongoose.connection.on('connected', () => { ? ?
? ?console.log('Mongoose connection open to ' + DB_URL); ?
}); ? ?
// 給事件 error 綁定處理函數,當連接錯誤時執行
mongoose.connection.on('error', (err) => { ? ?
? ?console.log('Mongoose connection error: ' + err); ?
}); ? ?
// 給事件 disconnected 綁定處理函數,當連接斷開時執行
mongoose.connection.on('disconnected', () => { ? ?
? ?console.log('Mongoose connection disconnected'); ?
});
~~~
注意:
* 上面代碼執行完之后,相當于在程序與數據庫之間架起一座橋梁,只有這橋梁架設好了,才能使用代碼完成對數據庫的操作,且這橋梁的只需架設一次就好了。
* 上述只最簡單的連接形式,當然還有其它形式,比如:設置連接密碼等,更多參考([https://mongoosejs.com/docs/api.html#index-js](https://mongoosejs.com/docs/api.html#index-js))。
# Mongoose 中的術語
* Schema:Mongoose 中的所有內容都以 Schema 開頭。每個 Schema 都映射到 MongoDB 集合,并定義該集合中文檔的結構。
* Model:由 Schema 生成的模型,其實例稱為 Document。**一般用來負責從 MongoDB 查詢文檔,修改文檔,刪除文檔**。
* Document:Mongoose 中 Document 與存儲在 MongoDB中 的文檔的一對一映射。每個文檔都是其模型的一個實例。**一般用來負責向 MongoDB 保存文檔**。
Schema 類型:
* String
* Number
* Date
* Boolean
* Array
* ObjectId
* Buffer
* Mixed
* Decimal128
* Map
~~~
// 編寫 StudentModel.js,文件位置 mongoose-demo/02.StudentModel.js,內容如下:
require('./01.db.js');
const mongoose = require('mongoose');
?
// 定義 Schema
const StudentSchema = new mongoose.Schema({
? ?name: String,
? ?age: Number,
? ?score: Number
});
?
// 根據 Schema 編譯 Model
// 第一個參數是 MongoDB 中集合的名字,可以不加 "s",默認找的時候會加上的
// 第二個參數是 Schema
// 若后面保存發現數據庫沒有對應 students 集合會自動創建
const StudentModel = mongoose.model('student', StudentSchema);
// 導出,因為模型在項目會多個地方使用,而定義的話就需一次就可以了,避免定義重復
module.exports = StudentModel;
~~~
# 常用操作
操作之前,須建立數據庫連接,及創建對應的模型。
## 新增文檔
### 方法
* Document.save(\[fn\]):新增文檔
### 代碼實現
~~~
// 編寫 save.js,文件位置 mongoose-demo,內容如下:
const StudentModel = require("./02.StudentModel.js");
?
function save() {
? ?// 根據 Model 創建文檔
? ?let student = new StudentModel({
? ? ? ?name : 'Jerry', ? ? ? ? ? ? ? ?
? ? ? ?age: 17, ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ?score: 78
? });
? ?// 向數據庫插入文檔,若有錯,err 有值,若沒有 res 是插入的返回結果
? ?student.save((err, res) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log("Res:" + res);
? });
}
save();
~~~
## 修改文檔
常見需求是根據 id 對文檔進行修改。
### 方法
* Model.findByIdAndUpdate(id, \[update\], \[options\], \[callback\])
* Model.update(conditions, update, \[options\], \[callback\])
### 代碼實現
~~~
// 在 student.js 中以下內容:
function update(){
? ?let conditions = {name : 'jerry'};
? ?let update = {score : 99};
? ?let options = { multi: false}; // 默認只改一條,若改成 true,則可改多條
? ?// 更多選項參考,https://mongoosejs.com/docs/api.html#model_Model.update
? ?StudentModel.update(conditions, update, options, (err, res) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log("Res:" + res);
? });
}
update();
?
function updateById(){
? ?let id = '5c73af7ed0ccdb347c899f38';
? ?var update = {name : 'Tom'};
? ?// 修改文檔,修改的話,res 是修改前文檔數據,若該 id 值對應的文檔不存在的話,res 是 null
? ?StudentModel.findByIdAndUpdate(id, update, (err, res) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log("Res:" + res);
? });
}
updateById();
~~~
## 刪除文檔
常見需求是根據 id 刪除文檔。
### 方法
* Model.findByIdAndRemove(id, \[options\], \[callback\])
* Model.remove(conditions, \[callback\])
* Model.findOneAndRemove(conditions, \[options\], \[callback\])
### 代碼實現
~~~
function deleteById(){
? ?let id = '5c73af7ed0ccdb347c899f38';
? ?// 刪除文檔,若刪除成功,res 是被刪除的文檔數據,若根據 id 沒查詢到,res 是 null
? ?StudentModel.findByIdAndRemove(id, (err, res) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log("Res:" + res);
? });
}
deleteById();
~~~
## 查詢文檔
常見需求是根據 id 查詢,根據單個條件查詢,也可以多個條件,也有查詢數據、查詢數量,即完成高級查詢和分頁查詢。
### 方法
* Model.findById(id, \[fields\], \[options\], \[callback\])
* Model.count(conditions, \[callback\])
* Model.find(conditions, \[fields\], \[options\], \[callback\])
### 代碼實現
~~~
// 根據 id 查詢出文檔
function getById(){
? ?let id = '5c73ae519d85483d4ce0836e';
? ?let fields = {"name" : 1, "_id" : 0} // 表示要查詢的字段,1 表示要查詢,0 表示不要查詢
? ?// 若查詢到 data 是文檔數據,若沒查詢 data 是 null
? ?StudentModel.findById(id, fields, (err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
}
getById();
~~~
~~~
// 查詢出所有文檔
function selectAll(){
? ?StudentModel.find({}, (err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
? ?/* 鏈式操作
? StudentModel.find({}).exec((err, data) => {
? ? ? if (err) {
? ? ? ? ? console.log("Error:" + err);
? ? ? ? ? return;
? ? ? }
? ? ? console.log(data);
? });*/
}
selectAll();
~~~
~~~
function query() {
? ?// 根據分數范圍查詢文檔
? ?let conditions1 = {score : {$gte : 18 , $lte : 20}};
? ?StudentModel.find(conditions1).exec((err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
?
? ?// 根據名字模糊查詢
? ?let conditions2 = {$or : [{name : {$regex : /r/i}}]}; // i 表示不區分大小寫
? ?StudentModel.find(conditions2, (err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
? ?// 正則表達式后面 i 是表示忽略大小寫
? ?let conditions3 = {score : {$gte : 18 , $lte : 20}, $or : [{name : {$regex : /x/i}}]};
? ?StudentModel.find(conditions3, (err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
}
query();
~~~
~~~
// 分頁查詢查詢文檔
function page(){
? ?let currentPage = 1; ? ? ? ? ? ? ? ? ? ? ? ?// 當前第幾頁
? ?let pageSize = 5; ? ? ? ? ? ? ? ? ? ? ? ? ? // 一頁多少條
? ?let sort = {score : -1}; ? ? ? ? ? ? ? ? ? ?// 1 表示升序,-1 表示降序
? ?let condition = {}; ? ? ? ? ? ? ? ? ? ? ? ? // 條件
? ?let skip = (currentPage - 1) * pageSize; ? ?//跳過數
?
? ?StudentModel.find(condition).skip(skip).limit(pageSize).sort(sort).exec((err, data) => {
? ? ? ?if (err) {
? ? ? ? ? ?console.log("Error:" + err);
? ? ? ? ? ?return;
? ? ? }
? ? ? ?console.log(data);
? });
}
page();
~~~
# 總結
Web 應用啟動之后不會斷了數據庫連接的,連接只要創建一次,Model 也在項目只要創建一次就夠了。