虽然 NodeJS 的模块和开发资源相当多,但相关文件却非常不足或是不完整,多半文献都只着重于基础的使用和片断的说明,如果不去看源代码,使用 NodeJS 来完成实用的网站,会有很大的困难度。对于已经有过 Web 开发经验的人,转换使用 NodeJS 不免也需要花一番功夫,过去经验中许多的常用的功能,都仍要一一花大量时间尝试才得以解决。而这样的情况,对于开发者来说相当的糟,也是很多人重新再评估是否使用 NodeJS 的重点因素之一。有道是”一人得道,鸡犬升天”,因此笔者未来将尝试将自己的实际经验,写成一篇篇重点功能实现的文章和随 Copy 即用的范例,减少其他人浪费同样的时间再摸索。
开发一个 Web 应用程序,最重要的莫过于数据库的使用,过去 PHP 有 MySQL 当最佳伙伴,而现在 NodeJS 有 MongoDB 做最佳的组合。MongoDB 是 NoSQL 的代表之一,其采用 JSON/BSON 当做数据储存和沟通的格式,亦使用 JavaScript 做为 Server-side 的执行程序语言(相当于传统 RDBMS 的预储程序),一切设计和习惯与 NodeJS 搭配使用起来,简直绝配。若你对 MongoDB 的一些基本操作有疑问,可以先参考旧文”MongoDB 快速笔记”。
使用 MongoDB
MongoDB 拥有 NoSQL 的普遍特色,不用预先定义 Schema,所有的 database 和 collection(相当于传统 RDBMS 的 Table),都会在新增数据后,自动被建立,我们只要专注于使用 NodeJS 操作数据库即可。
要在 NodeJS 里使用 MongoDB,可以安装 mongodb native driver,若透过 npm 来安装:
npm install mongodb
然后可以使用 NodeJS 建立 MongoDB connection pool ,做一些基础的操作:
var mongodb = require('mongodb'); var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 }); var db = new mongodb.Db('mydb', mongodbServer); /* open db */ db.open(function() { /* Select 'contact' collection */ db.collection('contact', function(err, collection) { /* Insert a data */ collection.insert({ name: 'Fred Chien', email: 'cfsghost@gmail.com', tel: [ '0926xxx5xx', '0912xx11xx' ] }, function(err, data) { if (data) { console.log('Successfully Insert'); } else { console.log('Failed to Insert'); } }); /* Querying */ collection.find({ name: 'Fred Chien' }, function(err, data) { /* Found this People */ if (data) { console.log('Name: ' + data.name + ', email: ' + data.email); } else { console.log('Cannot found'); } }); }); });
注:这是 MongoDB 的基本常识,每当新增一笔数据,MongoDB 会自动帮该笔数据加上 _id 字段,并给与一个唯一值(格式是 ObjectId),所以我们不需要像过去 使用 SQL Server 一般,自己刻意去定义一个 ID 字段。
预设的 ObjectId 范围太小,改用 UUID 来当数据的唯一 ID
如果你过去有过 Web 开发经验,到这边肯定会开始有一些疑问欲求解,第一个问题肯定是”ObjectId 的数量极限?”。笔者在此不会回答这问题,因为这答案并不重要,想要准确知道答案,可以去”
mongodb.org“寻找答案。
比起上述问题,相信你应该更想问:
预设的 ObjectId 适用的范围? 如果日后数据库要扩展(Scale),是否有其他的 ID 解决方案可使用?
一般情况, MongoDB 预设的 ObjectId 就相当够用了,但如果你是要建构大型的 Web Service 或是保留未来的扩充性,可使用 UUID 去代替 ObjectId。不过,因为 MongoDB 本身并不生成 UUID,若是要使用 UUID,就必需先自行产生好 UUID,然后在新增数据时指定生成好的 UUID 给 _id 字段,让 MongoDB 改用我们给的 ID 而不使用预设生成的 ObjectId。
因为要自行产生 UUID,必需先为 NodeJS 安装模块 node-uuid:
npm install uuid
然后生成 UUID 并在 insert 时使用:
var uuid = require('node-uuid'); var mongodb = require('mongodb'); var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 }); var db = new mongodb.Db('mydb', mongodbServer); /* open db */ db.open(function() { /* Select 'contact' collection */ db.collection('contact', function(err, collection) { /* Generate UUID(16 Bytes) and convert to BinaryData object for mongodb */ var uuidBinary = new Buffer(uuid.v1({}, [])); var id = mongodb.BSONPure.Binary(uuidBinary, mongodb.BSONPure.Binary.SUBTYPE_UUID); /* Insert a data with uuid */ collection.insert({ _id: id, name: 'Fred Chien', email: 'cfsghost@gmail.com' }, function(err, data) { if (data) { console.log('Successfully Insert'); } else { console.log('Failed to Insert'); } }); }); });
你可能会发现,在上面的范例程序中,我们将 UUID 转成 MongoDB BSON 的 BinaryData 格式,这是为了效能考虑,因为用纯字符串当做 Unique ID,在数据库搜寻上会比 BinaryData Object 慢很多。
储存时间戳(Timestamp)
关于储存时间的问题,如果你去各大 MongoDB 讨论区询问或查询,通常大家都会告诉你不必做这件事,因为每一笔数据被建立后,自动产生的 ObjectId 就包含了建立的时间讯息,我们只要去学习如何从中去解析时间即可。但是,不单只是建立时间,有时我们会为数据加上各种不同的时间戳,如:更新时间等,所以,储存时间戳还是必要的。
虽然网络上相关 NodeJS 范例并不多,但 MongoDB 确实有 Timestamp 的数据结构可以用,我们可以这样使用:
var uuid = require('node-uuid'); var mongodb = require('mongodb'); var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 }); var db = new mongodb.Db('mydb', mongodbServer); /* open db */ db.open(function() { /* Select 'contact' collection */ db.collection('contact', function(err, collection) { /* Generate Timestamp and convert for mongodb */ var ts = new Date().getTime(); var i = ts % 1000; var t = new mongodb.BSONPure.Timestamp(i, Math.floor(ts * 0.001)); /* Insert a data with uuid */ collection.insert({ name: 'Fred Chien', email: 'cfsghost@gmail.com', created: t }, function(err, data) { if (data) { console.log('Successfully Insert'); } else { console.log('Failed to Insert'); } }); }); });
建立数据库索引(Index)
过去有接触过数据库的人应该都很清楚,索引(Index)是能优化数据查询速度的重要功能,MongoDB 同样也有索引的设计。
可以在 NodeJS 中,这样为 name 字段加上索引:
collection.createIndex({ name: 1 });
后记