GitHub源码链接:sodino#MongoDemo


理解Schema

传统的MySQL、Oracle等关系型数据库中,在存储数据之前,开发者必须道德为数据定义数据表,并且为该数据表定义一些字段,从而使数据模型得到实现。
可以说,在关系型数据库中,一个数据表就是一个数据架构。它预先定义了开发者可以使用的数据模型。

但MongoDB是面向文档的数据库,不是关系型数据库。被认为是无数据架构的。

然而数据架构仍然是有用的,可以使人以易读的方式来描述数据库中的数据内容,并为这些数据定义一些规则。
如Mongoose可以对Number的数据设置最小值min与最大值max;可以对Date设置默认值为当前时间;可以对String设置存储为小写模式并去除头尾空白字符。

而以上所说的功能都在Mongoose的设计理念中,都由Schema的定义来实现。


Schema的定义

在Sodino的MongoDemo工程中,需要对手机进行数据架构的定义。具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 准备工作
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// 开始定义Schema
var phoneSchema = new Schema({
device : String, //设备名称
isSmart : Boolean, //是否为智能手机
releaseTime : Date, //发布时间
price : Number, //售价
apps : [{name : String}], //手机中安装的App名称,是数组
manufacturer: { //手机厂商
name : String, //厂商名称
country : String //厂商国籍
}
});

至此,对手机的Schema定义完成。
当然,也可能通过Api对Schema进行动态扩展,如需要增加手机的颜色这一数据属性,则可以用如下代码实现:

1
phoneSchma.add({color : 'string'})

Schema中所支持的数据类型有:

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • Objectid
  • Array

创建Model

下一步在代码中使用Schema所定义的数据模型,需要将定义好的phoneSchema转换为Model
可以使用mongoose.model(modelName, schema)进行转换。

1
var Phone = mongoose.model('Phone', phoneSchema);

Schema后为什么还要有Model呢?
在Mongoose的设计理念中,Schema用来也只用来定义数据结构,具体对数据的增删改查操作都由Model来执行。
就好比富士康用模具组装出一台手机后,当需要打电话时是用手机来打而不是用模具。


创建数据实例

Model相当于数据的构造函数。当需要实例化出一个数据对象实例时,可以使用new操作符来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
var iPhoneSE = new Phone(
{
device : "iPhone SE",
isSmart : "true",
releaseTime : "2016-03-21 10:00:00",
price : 4999,
apps : [{name : "Safari"}, {name : "Map"}, {name : "Tinder"}],
manufacturer: {
name : "Apple",
country" : "The United States"
}
}
);

在上面的代码中,数据的具体值以JSON对象的形式作为参数传入Phone即构造出数据对象实例iPhoneSE

sodino#MongoDemo示例代码中,Sodino使用了require(json.file.path)来获取JSON对象再传参到Phone的方式。简化了JavaScript的代码量。

1
2
3
4
// raw.iPhoneSe.json与当前的js代码文件放于同一目录下
var raw;
raw = require('./raw.iPhoneSE.json');
var iPhoneSE = new Phone(raw);
1
2
3
4
5
6
7
8
9
10
11
12
// raw.iPhoneSe.json内容如下:
{
"device" : "iPhone SE",
"isSmart" : "true",
"releaseTime" : "2016-03-21 10:00:00",
"price" : 4999,
"apps" : [{"name" : "Safari"}, {"name" : "Map"}, {"name" : "Tinder"}],
"manufacturer": {
"name" : "Apple",
"country" : "The United States"
}
}

Model实例方法

可以为Model的实例添加自定义方法,作法也很简单,只要将自定义的方法添加到Schema.methods即可。

可以设想这样的功能,Phone的内容很多,但客户最关心哪个手机价格是多少,那么可以添加一个实例方法printBrief()用来打印出这两个信息就好了。

如下代码所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var phoneSchema = new Schema({
... ...
... ...
});
var Phone = mongoose.model('Phone', phoneSchema);
// 这里,为Model添加实例方法。
phoneSchema.methods.printBrief = function () {
console.log(this.device, '¥'+this.price);
};

printBrief()的使用方法如下:

1
2
3
var iPhoneSE = new Phone(raw);
iPhoneSE.printBrief();

控制台输出为:

1
iPhone SE ¥ 4999

需要注意的是,Model实例方法只能被Model的实例调用,不能被Model直接调用,否则会抛出is not a function异常。这相当于Java的非静态方法不能被Class直接调用。异常如下所示:

1
TypeError: Phone.printBrief is not a function at Query.<anonymous> (D:\desk\JavaScript\MongoDemo\app.js:427:14) at D:\desk\JavaScript\MongoDemo\node_modules\kareem\index.js:177:19 at D:\desk\JavaScript\MongoDemo\node_modules\kareem\index.js:109:16 at _combinedTickCallback (node.js:370:9) at process._tickCallback (node.js:401:11)

Model静态方法

与实例方法相对应的是静态方法。只要在Schema.statics中添加新声明的方法即可。

可以设想这样的功能,想查询一下Phone到底存储了多少个手机型号,可以定义一个静态方法printCount(),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var phoneSchema = new Schema({
... ...
... ...
});
var Phone = mongoose.model('Phone', phoneSchema);
// 这里,为Model添加静态方法。
phoneSchema.statics.printCount = function () {
console.log(this.device, '¥'+this.price);
this.count({}, (err, count) => {
console.log('---printCount()-----------------------------')
if (err) {
console.log(err);
} else {
console.log('phone count=' + count);
}
});
};

调用方法如下:

1
Phone.printCount();

控制台打印如下:

1
---printCount()----------------------------- phone count=5

说了这么多,接下来的文章开始介绍数据库的增删改查了哈…

下一篇:mongoose教程–存储


相关链接

Mongoose Quick Start v4.4.19
Mongoose Schemas v4.4.19


About Sodino