mongoose基础

在Nodejs开发中,我们一般使用mongoose来操作mongoDB数据库。下面我么来学习下mongoose常用的用法。

准备工作

那要使用它,首先你得装上node.js和mongodb并启动mongodb数据库

Github地址:https://github.com/Automattic/mongoose

API Docs:http://mongoosejs.com/docs/guide.html

概念理解

要学习mongoose首先要了解三个重要的概念,他们是Schema、Model、Document。它们的关系是Schema生成Model、Model创造Document。

Schema类似于定义表结构,但并不完全准确。它用于创建表时的数据定义(不仅仅可以定义文档的结构和属性,还可以定义文档的实例方法、静态模型方法、复合索引等),每个Schema会映射到mongodb中的一个collection。Schema不具备操作数据库的能力,主要用于定义结构。

Model是由Schema编译而成的构造器,具有抽象属性和行为,可以对数据库进行增删查改。Model所能增删查改的具体值是由Schema定义的,Schema定义以外的值则没有效果。在mongoDB中一个数据库有多个collections(由Schema定义结构),而每个collections有多个document(类似js对象一般的键值对)。

Model的每一个实例(instance)就是一个文档document。Document是由Model创建的实体,它的操作也会影响数据库。

连接数据库

在使用前首先连接数据库(若没有则创建之)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/test');
//已连接
mongoose.connection.on('connected', function () {
console.log('已连接');
});
//连接错误
mongoose.connection.on('error',function (err) {
console.log('出错');
});
//断开连接
mongoose.connection.on('disconnected', function () {
console.log('断开连接');
});

其它事件可以自行查看:http://mongoosejs.com/docs/api.html#connection_Connection

定义Schema

Schema是mongoose中需要事先定义的数据模式,类似于表结构,不过mongoDB中不叫表,叫collections。

模型可以看作mysql中的数据表,属性可以看作是字段,当然这个类比并不十分正确。

每个Schema对应当前连接的数据库的一个collection,若不存在则会自动创建。

Schema不具备操作数据库的能力。

下面我们来看下如何创建Schema

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var mongoose = require('mongoose');
Schema = mongoose.Schema;

var blogSchema = new Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
});

type有下面这些,StringNumberBooleanArrayBufferDateObjectIdMixed类型

生成Model

模型Model是根据Schema编译出的构造器,或者称为类,通过Model可以实例化出文档对象document。

下面根据Schema构建一个Model

1
var Blog = mongoose.model('Blog', blogSchema);

Model实例化之后为document。

1
2
3
var blogInstance = new Blog({
...
});

常用数据库操作

新增

document.save()

model实例化后的document可用save新增文档

1
2
3
4
5
6
7
8
9
10
11
12
13
//实例化model
var blogInstance = new Blog({
...
});
//调用save方法即插入一个新的document
user.save(function (err, res) {
if (err) {
console.log("Error:" + err);
}
else {
console.log("Res:" + res);
}
});

model.create()

使用save()方法,需要先实例化为文档,再使用save()方法保存文档。而create()方法,则直接在模型Model上操作,并且可以同时新增多个文档

1
2
3
4
Blog.create({name:"xiaowang"},{name:"xiaoli"},function(err,doc1,doc2){
console.log(doc1);
console.log(doc2);
});

查询

查询文档有以下三种方法

1
2
3
find()
findById()
findOne()

find()
第一个参数表示查询条件,第二个参数用于控制返回的字段,第三个参数用于配置查询参数,第四个参数是回调函数,回调函数的形式为function(err,docs){}

1
Model.find(conditions, [projection], [options], [callback])

findById()

1
Model.findById(id, [projection], [options], [callback])

findOne()
该方法返回查找到的所有实例的第一个

1
Model.findOne([conditions], [projection], [options], [callback])

更新

更新文档有以下两种方法

1
2
update()
updateMany()

update()
第一个参数conditions为查询条件,第二个参数doc为需要修改的数据,第三个参数options为控制选项,第四个参数是回调函数

1
Model.update(conditions, doc, [options], [callback])

updateMany()
updateMany()与update()方法唯一的区别就是默认更新多个文档,即使设置{multi:false}也无法只更新第一个文档

1
Model.updateMany(conditions, doc, [options], [callback])

删除

更新文档有以下三种方法

1
2
3
remove()
findOneAndRemove()
findByIdAndRemove()

remove()

remove有两种形式,一种是文档的remove()方法,一种是Model的remove()方法。

下面介绍Model的remove()方法,该方法的第一个参数conditions为查询条件,第二个参数回调函数的形式如下function(err){}。

1
model.remove(conditions, [callback])

下面介绍文档的remove()方法,该方法的参数回调函数的形式如下function(err,doc){}

1
document.remove([callback])

findOneAndRemove()
model的remove()会删除符合条件的所有数据,如果只删除符合条件的第一条数据,则可以使用model的findOneAndRemove()方法

1
Model.findOneAndRemove(conditions, [options], [callback])

findByIdAndRemove()

1
Model.findByIdAndRemove(id, [options], [callback])

前后钩子

前后钩子即pre()和post()方法,又称为中间件,是在执行某些操作时可以执行的函数。中间件在schema上指定,类似于静态方法或实例方法等

可以在数据库执行下列操作时,设置前后钩子

1
2
3
4
5
6
7
8
9
10
11
init
validate
save
remove
count
find
findOne
findOneAndRemove
findOneAndUpdate
insertMany
update

pre()
以find()方法为例,在执行find()方法之前,执行pre()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});  
schema.pre('find',function(next){
console.log('我是pre方法1');
next();
});
schema.pre('find',function(next){
console.log('我是pre方法2');
next();
});
var temp = mongoose.model('temp', schema);
temp.find(function(err,docs){
console.log(docs[0]);
})
/*
我是pre方法1
我是pre方法2
{ _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 }
*/

查询后处理

常用的查询后处理的方法如下所示

1
2
3
4
5
6
7
sort     排序
skip 跳过
limit 限制
select 显示字段
exect 执行
count 计数
distinct 去重

例子

1
2
3
4
//按照age从小到大排列
temp.find().sort("age").exec(function(err,docs){
console.log(docs);
});

文档验证

如果不进行文档验证,保存文档时,就可以不按照Schema设置的字段进行设置,分为以下几种情况

  1. 缺少字段的文档可以保存成功
  2. 包含未设置的字段的文档也可以保存成功,未设置的字段不被保存
  3. 包含字段类型与设置不同的字段的文档也可以保存成功,不同字段类型的字段被保存为设置的字段类型

而通过文档验证,就可以避免以上几种情况发生

文档验证在SchemaType中定义,格式如下

1
{ name: {type:String, validator:value} }

常用验证包括以下几种

1
2
3
4
5
6
7
required: 数据必须填写
default: 默认值
validate: 自定义匹配
min: 最小值(只适用于数字)
max: 最大值(只适用于数字)
match: 正则匹配(只适用于字符串)
enum: 枚举匹配(只适用于字符串)

参考

Mongoose基础入门

Mongoose介绍和入门