# 简介
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 也在项目只要创建一次就够了。