[TOC]
1. MongoDB简介
- MongoDB是一个开源的NoSQL数据库;
- 同时它也是一个对象数据库,没有固定的模式和结构;
- 所有的数据以文档的形式存储,数据格式就是JSON。
2. Mongoose是什么?
Mongoose
是MongoDB
的一个对象模型工具;- 同时它也是针对
MongoDB
操作的一个对象模型库,封装了MongoDB
对文档的的一些增删改查等常用方法; - 让
NodeJS
操作Mongodb
数据库变得更加灵活简单。
3. Mongoose模块介绍
mongoose模块用来将nodejs中的对象与mongodb中的文档进行对应的模块。
Mongoose
是在node.js
异步环境下对mongodb
进行便捷操作的对象模型工具。那么要使用它,首先你得装上node.js
和mongodb
。
3.1 mongoose安装
npm install mongoose
安装成功后,就可以通过require('mongoose')
来使用。
官网实例:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
const Cat = mongoose.model('Cat', { name: String });
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
2
3
4
5
6
7
Mongoose
提供了一个直观的,基于模式的解决方案来建模应用程序数据。它包括内置的类型转换,验证,查询构建,业务逻辑挂钩等,开箱即用;是mongoDB
的好基友。
为了保存网站的用户数据和业务数据,通常需要一个数据库。MongoDB和Node.js
特别般配,因为mongodb
是基于文档的非关系型数据库,文档是按BSON
(JSON的轻量化二进制格式)存储的,增删改查等管理数据库的命令和JavaScript
语法很像。如果你在node.js
里访问MongoDB
的数据,会有我们是一家人的感觉,特别亲切。
MongoDB
使用集合(collection)和文档(document)来描述和存储数据,collection就相当于表,document相当于行,不过MySQL之类的关系型数据库,表结构是固定的,比如某一行由若干列组成,行行都一样,而MongoDB不同,一个集合里的多个文档可以有不同的结构,更灵活一些。
4. 配置与连接
创建一个db.js:
// 引入mongoose
const mongoose = require('mongoose');
// 连接字符串
const DB_URL = 'mongodb://localhost:27017/mongoosesample';
const db = mongoose.connection;
// 连接数据库
mongoose.connect(DB_URL, {useNewUrlParser: true});
// 连接成功
db.on('connected', () => {
console.log('Mongoose connection open to:' + DB_URL);
});
// 连接失败
db.on('error', err => {
console.log('Mongoose connection error:' + err);
});
// 连接断开
db.on('disconnected', () => {
console.log('Mongoose connection disconnected');
});
module.exports = mongoose;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const mongoose = require('mongoose');
const DB_URL = 'mongodb://localhost:27017/mongoosesample';
/**
* 连接
*/
mongoose.connect(DB_URL);
/**
* 连接成功
*/
mongoose.connection.on('connected', () => {
console.log('Mongoose connection open to ' + DB_URL);
});
/**
* 连接异常
*/
mongoose.connection.on('error', (err) => {
console.log('Mongoose connection error: ' + err);
});
/**
* 连接断开
*/
mongoose.connection.on('disconnected', () => {
console.log('Mongoose connection disconnected');
});
module.exports = mongoose;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
5. Modal与Schema
5.1 Schema
Schema
是数据库集合的模型骨架,定义了集合中的字段的名称和类型以及默认值等信息。
schema
是mongoose
里会用到的一种数据模式,可以理解为表结构的定义;每个schema
会映射到mongodb
中的一个collection
,它不具备操作数据库的能力。我们先改造一下db.js,导出mongoose对象。
5.2 Schema.Type
NodeJS
中的基本数据类型都属于Schema.Type
。另外Mongoose
还定义了自己的类型,基本属性类型有:
- 字符串(String)
- 日期型(Date)
- 数值型(Number)
- 布尔型(Boolean)
- null
- 数组([])
- 内嵌文档
定义Schema:
const personSchema = new Schema({
name: String, //姓名
binary: Buffer, //二进制
living: Boolean, //是否活着
birthday: Date, //生日
age: Number, //年龄
_id: Schema.Types.ObjectId, //主键
_fk: Schema.Types.ObjectId, //外键
array: [], //数组
arrOfString: [String], //字符串数组
arrOfNumber: [Number], //数字数组
arrOfDate: [Date], //日期数组
arrOfBuffer: [Buffer], //Buffer数组
arrOfBoolean: [Boolean], //布尔值数组
arrOfObjectId: [Schema.Types.ObjectId] //对象ID数组
nested: { //内嵌文档
name: String,
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
5.3 Model
Model
是由通过Schema
构造而成,除了具有Schema
定义的数据库骨架以外,还可以操作数据库。如何通过Schema
来创建Model
呢,如下:
// 连接数据库
mongoose.connect("mongodb://123.57.143.189:27017/zfpx");
// 两个参数表示定义一个模型
// PersonSchema是定义好的Schema
// Person是Modal的名称,第一个字母要大写
const PersonModel = mongoose.model("Person", PersonSchema);
// 如果该Model已经定义,则可以直接通过名字获取
const PersonModel = mongoose.model('Person'); // 一个参数表示获取已定义的模型
2
3
4
5
6
7
8
拥有了Model
,我们也就拥有了操作数据库的能力。
在数据库中的集合名称等于模型名转小写再转复数,比如Person>person>people,Child>child>children。
在上例中,我们的模型名称为
Person
,最后的collection
的名称为people
。
6. 创建文档
7. 删除文档
8. 简单查询
9. 条件语句
mongoose增删改查Demo
在项目中安装mongoose:
cnpm install mongoose // 或者
yarn add mongoose
2
做个简单项目的项目结构,对数据的增删改查,都是简单的操作,主要是引入mongoose的链接操作,复杂的增删改查在MongoDB的基础知识中学习。
目录结构如下:
MongoDB数据库框架mongoose
db.js 连接数据库
Model.js 构建模型骨架,构建Model
insert.js 插入数据(增)
delete.js 删除数据(删)
update.js 修改数据(改)
find.js 查询数据(查)
MongoDB可视化工具robo 3t
2
3
4
5
6
7
8
9
10
11
12
13
14
15
连接数据库
连接数据库,创建db.js文件
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/user', { useNewUrlParser: true });
// 连接失败
mongoose.connection.on('error', err => {
console.error('数据库链接失败:' + err);
});
// 连接成功
mongoose.connection.on('open', () => {
console.log('数据库链接成功');
});
// 断开数据库
mongoose.connection.on('disconnected', () => {
console.log('数据库断开成功');
})
// 将mongoose导出
module.exports = mongoose;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
构建模型骨架Schame
构建模型骨架Schame,构建Model,创建文件Model.js:
const mongoose = require('./db.js');
// 模型骨架
const Schema = new mongoose.Schema({
username: {type: String},
age: {type: Number, default: 10},
address: {type: String},
time: {type: Date} // 创建时间
});
// 定义好了Schema,接下就是生成Model。model是由schema生成的模型,可以对数据库的操作。
// 由schema构造生成Model
const Model = mongoose.model('user', Schema);
module.exports = Model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
定义一个Schema就这么简单,指定字段名和类型。Schema Types内置类型如下:
- String
- Number
- Boolean | Bool
- Array
- Buffer
- Date
- ObjectId | Oid
- Mixed
插入数据
增加数据,创建文件insert.js:
const Model = require('./Model.js');
// 插入数据
Model.create([
{
username: 'wangwu',
age: 33,
address: 'tianjin',
time: new Date()
}
], (err, res) => {
if (err) {
console.error(err);
}
else {
console.log('插入数据成功');
console.log(res);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
删除数据
删除数据, 创建文件delete.js:
const Model = require('./Model.js');
// 删除数据
Model.deleteOne({username: 'zhaoliu'}, (err, res) => {
if(err) {
console.error(err);
}
else {
console.log(res);
}
});
2
3
4
5
6
7
8
9
10
11
修改数据
修改数据, 创建文件 update.js:
const Model = require('./Model.js');
// 更新数据
Model.updateOne({username: 'liutao'}, {age: 62}, (err, res) => {
if(err) {
console.error('Error: ' + err);
return;
}
console.log(res);
});
2
3
4
5
6
7
8
9
查询数据
查询数据,创建文件
find.js
:
// 引入模型
const Model = require('./Model.js');
// 查询数据(通过调用模型的find方法)
// find函数的第一个参数是查询条件,第二个参数是查询操作完成后的回调,回调函数的第一个参数是查询出错后的错误对象,第二个参数是查询的结果。
// 当第一个参数为{}空对象时,可以返回所有结果
Model.find({username: 'liutao'}, (err, res) => {
if(err){
console.log(err);
return;
}
console.log(res);
})
2
3
4
5
6
7
8
9
10
11
12
13
findOne
findOne()方法:只返回符合查询条件的第一条数据。
const Model = require('./Model.js');
// 查询数据
Model.findOne({username: 'liutao'}, (err, res) => {
if(err){
console.log(err);
}
else {
console.log(res);
}
});
2
3
4
5
6
7
8
9
10
11
条件查询
const Person = require('./Model.js');
// 查询username为lisi或者wangwu的数据
const cond = {
$or: [
{username: 'lisi'},
{username: 'wangwu'}
]
};
Person.find(cond, (err, res) => {
if(err){
console.log(err);
return;
}
console.log('cond:', cond, 'res:', res);
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Mongoose 使用进阶
模式的扩展
默认值
默认值的类型:
- 固定值
- 即时生成
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
username: {type: String, default: 'lisi'},
age: {type: Number, default: 12},
address: {type: String, default: 'beijing'},
time: {type: Date, default: Date.now}
});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
const person = new Person(); // 这里不传参数将使用Modal的默认值
console.log(person);
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
模式修饰符
- 预定义的模式修饰符(例如:去除字段值两侧的空格)
- 自定义setter修饰符
- 自定义getter修饰符
setter.js
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
username: {
type: String,
trim: true // 去空格(预定义的模式修饰符)
},
age: {type: Number}
});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
const person = new Person({
username: ' zhaoliu ',
age: 20
});
console.log(person);
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
如上图所示:username左右两侧的空格被去除了。
自定义setter修饰符demo:
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
username: {
type: String,
trim: true // 去空格
},
age: {type: Number},
blog: {
type: String,
set: url => { // 如果blog前面没有协议,则默认添加'http://'
if (!url) return url;
if (url.indexOf('http://') !== 0 && url.indexOf('https://') !== 0) {
url = 'http://' + url;
}
return url;
}
}
});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
const person = new Person({
username: ' zhaoliu ',
age: 20,
blog: 'www.baidu.com'
});
console.log(person);
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
如上图所示,blog字段前面加上了相应的协议。
自定义getter修饰符demo:
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
blog: {
type: String,
get: url => { // 如果blog前面没有协议,则默认添加'http://'
if (!url) return url;
if (url.indexOf('http://') !== 0 || url.indexOf('https://') !== 0) {
url = 'http://' + url;
}
return url;
}
}
});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
const person = new Person({
blog: 'www.baidu.com' // 这里的值会传给get修饰符
});
console.log(person);
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
虚拟属性(使用Schema.virtual()方法创建)
virtual.js
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
fristName: String,
lastName: String
});
// 创建虚拟属性
PersonSchema.virtual('fullName').get(function() {
return this.fristName + ' ' + this.lastName;
});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
// 实例化
const person = new Person({
fristName: 'li',
lastName: 'si'
});
console.log('fullName:', person.fullName);
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
将person转为json:
const mongoose = require('./db.js');
// 模型骨架
const PersonSchema = new mongoose.Schema({
fristName: String,
lastName: String
});
// 创建虚拟属性
PersonSchema.virtual('fullName').get(function() {
return this.fristName + ' ' + this.lastName;
});
PersonSchema.set('toJSON', {getters: true, virtual: true});
// 由schema构造生成Model
const Person = mongoose.model('Person', PersonSchema);
// 实例化
const person = new Person({
fristName: 'li',
lastName: 'si'
});
console.log('fullName:', person.fullName);
console.log('JSON:', JSON.stringify(person));
module.exports = Person;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
索引
索引的目的
- 唯一索引
- 辅助索引(用来增加查询速度)
模型的方法
自定义静态方法:
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/book', { useNewUrlParser: true });
// 模型骨架
const BookSchema = new mongoose.Schema({
isbn: Number,
name: String
});
// 定义静态方法
BookSchema.statics.findByISBN = function(isbn, cb) {
this.findOne({isbn: isbn}, (err, doc) => {
cb(err, doc);
});
};
const Book = mongoose.model('Book', BookSchema);
const book = new Book({
name: '计算机程序设计',
isbn: 123456
});
book.save(err => {
if (err) {
return console.log('save book failed', err);
}
Book.findByISBN(123456, (err, doc) => {
console.log('findByISBN, err, doc:', err, doc);
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
自定义实例方法:
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/book', { useNewUrlParser: true });
// 模型骨架
const BookSchema = new mongoose.Schema({
isbn: Number,
name: String
});
// 定义静态方法
BookSchema.statics.findByISBN = function(isbn, cb) {
this.findOne({isbn: isbn}, (err, doc) => {
cb(err, doc);
});
};
// 定义实例方法
BookSchema.methods.print = function() {
console.log('Book info:');
console.log('\tTitle:', this.name);
console.log('\tISBN:', this.isbn);
};
const Book = mongoose.model('Book', BookSchema);
const book = new Book({
name: '计算机程序设计',
isbn: 123456
});
book.save(err => {
if (err) {
return console.log('save book failed', err);
}
Book.findByISBN(123456, (err, doc) => {
console.log('findByISBN, err, doc:', err, doc);
});
book.print(); // 调用实例方法
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
数据的校验
预定义的验证器:required,Number(max,min),String(enum,match)。
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/book', { useNewUrlParser: true });
// 模型骨架
const OrderSchema = new mongoose.Schema({
count: {
type: Number,
required: true, // 设置必须
max: 1000, // 设置最大值
min: 10 // 设置最小值
},
status: {
type: String,
enum: ['created', 'success', 'failed'] // 枚举验证器
},
desc: {
type: String,
match: /book/g, // 正则验证器,值中必须包含book字符串
validate: function(desc) { // 自定义验证器,必须大于10个字符
return desc.length >= 10;
}
}
});
const Order = mongoose.model('Order', OrderSchema);
const order = new Order();
order.count = 100;
order.status = 'success';
order.desc = 'test';
order.save(err => {
if (err) {
return console.log('save failed', err);
}
console.log('save success');
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
自定义验证器:
中间件
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/book', { useNewUrlParser: true });
// 模型骨架
const ResellerSchema = new mongoose.Schema({
address: String
});
ResellerSchema.post('save', function(next) {
console.log('我是后置中间件,在保存动作之后执行');
next();
});
ResellerSchema.pre('save', true, function(next, done) {
console.log('我是预处理中间件,在保存动作之前执行');
next();
done();
});
const Reseller = mongoose.model('Reseller', ResellerSchema);
const reseller = new Reseller({
address: 'beijing'
});
reseller.save();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DBRef
DBRef作用:在一个collection中引用另一个collection中的数据。实现集合数据的交叉引用。
// 连接数据库
const mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1:27017/book', { useNewUrlParser: true });
// 模型骨架
const UserSchema = new mongoose.Schema({
username: String
});
const NewsSchema = new mongoose.Schema({
title: String,
author: {
type: mongoose.Schema.ObjectId,
ref: 'User' // 指定使用User集合中的数据,通过ref指定将两个集合关联起来
}
});
const Users = mongoose.model('User', UserSchema);
const News = mongoose.model('News', NewsSchema);
const user = new Users({
username: 'lisi'
});
const news = new News({
title: '武侠小说',
author: user
});
user.save(err => {
if (err) {
return console.log('save failed', err);
}
news.save(err => {
if (err) {
return console.log('save news failed:', err);
}
News.findOne().populate('author').exec((err, doc) => {
console.log('save success:', doc);
});
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42