## 第十二步:数据库模式 在根目录新建目录models,然后进入目录并新建文件*character.js*: ~~~ var mongoose = require('mongoose'); var characterSchema = new mongoose.Schema({ characterId: { type: String, unique: true, index: true }, name: String, race: String, gender: String, bloodline: String, wins: { type: Number, default: 0 }, losses: { type: Number, default: 0 }, reports: { type: Number, default: 0 }, random: { type: [Number], index: '2d' }, voted: { type: Boolean, default: false } }); module.exports = mongoose.model('Character', characterSchema); ~~~ ![](https://box.kancloud.cn/2015-09-14_55f643b4dab4b.jpg) 一个模式(schema)是你的MongoDB数据库中的数据的一个表示,你能强迫某些字段必须为特定的类型,甚至决定该字段是否必需、唯一或者仅包含指定的元素。 和抽象的模式相比,一个模型(model)是和实践更接近的对象,包含添加、删除、查询、更新数据的方法,在上面,我们创建了一个Character模型并将它暴露出来。 > 注意:为什么这个教程仍然使用MongoDB?为什么不使用MySQL、PostgreSQL、CouchDB甚至[RethinkDB](http://rethinkdb.com/)?这是因为对于要构建的应用来说,我并不真正关心数据库层到底是什么样的。我更关注在前端的技术栈,因为这是我最感兴趣的部分。MongoDB也许并适合所有的使用场景,但它是一个合适的通用数据库,并且过去3年来我和它相处良好。 这里大多数字段都能自我解释,不过`random`和`voted`也许需要更多解释: * `random` – 从`[Math.random(), 0]`生成的包含两个数字的数组,这是一个MongoDB相关的[地理](http://docs.mongodb.org/manual/applications/geospatial-indexes/)标记,为了从数据库随机抓取一些角色,我们将使用[`$near`](http://docs.mongodb.org/manual/reference/operator/query/near/)操作符,我是从StackOverflow上[Random record from MongoDB](http://stackoverflow.com/questions/2824157/random-record-from-mongodb)学到这个技巧。 * `voted` – 一个布尔值,为确定角色是否已被投票。如果不设置的话,人们可能会给同一角色反复刷票,现在当请求两个角色时,只有那些没有被投票的角色会被获取。即使有人直接使用API,已投票的角色也不会再次被投票。 回到server.js,在文件开头添加下面的代码: ~~~ var mongoose = require('mongoose'); var Character = require('./models/character'); ~~~ 为了保证一致性和系统性,我经常按照下面的顺序导入模块: 1. 核心Node.js模块——path、querystring、http 2. 第三方NPM库——mongoose、express、request 3. 应用本身文件——controllers、models、config 最后,为链接到数据库,在依赖模块和Express中间件之间添加下面的代码,它将在我们启动Express app的时候发起一个到MongoDB的连接池: ~~~ mongoose.connect(config.database); mongoose.connection.on('error', function() { console.info('Error: Could not connect to MongoDB. Did you forget to run `mongod`?'); }); ~~~ > 注意:我们将在config.js中设置数据库的hostname以避免硬编码。 在根目录新建另一个文件*config.js*: ~~~ module.exports = { database: process.env.MONGO_URI || 'localhost' }; ~~~ 它将使用一个环境变量(如果可用)或降级到localhost,这将允许我们在本地开发时使用一个hostname,而在生产环境使用另一个,同时无需修改任何代码。这种方法对于[处理OAuth客户端key和secret](https://github.com/sahat/hackathon-starter/blob/master/config/secrets.js)时特别有用。 现在让我们将它导入到server.js中: ~~~ var config = require('./config'); ~~~ 在终端中打开一个新的标签并运行`mongod`。 ![](https://box.kancloud.cn/2015-09-14_55f643b558bcb.jpg)