gist

2012年1月14日土曜日

NodeでMongoDBを使って連絡帳アプリを作る


MongoDBはドキュメント指向のNoSQLデータベースです。Express、MongoDBを組み合わせて連絡帳ウェブアプリケーションを構築してみます。

システム構成

  • Mac OS X Lion
  • Node 0.6.7
  • MongoDB 2.0.2
  • フレームワーク: Express
  • HTMLテンプレート: jade

アクション一覧

アクション名URLメソッド説明
トップページ/GET一覧画面にリダイレクトします。
一覧画面表示/addressbookGET連絡先の一覧を表示します。
連絡先を選択すると詳細を表示します。
詳細画面表示/addressbook/show/:idGET連絡先の詳細を表示します。
編集画面表示/addressbook/edit/:idGET連絡先の編集フォームを表示します。
更新/addressbook/update/:idPOST連絡先を更新し、詳細に戻ります。
作成画面表示/addressbook/addGET連絡先の作成フォームを表示します。
作成/addressbook/insertPOST新しい連絡先を挿入し、
連絡先一覧に戻ります。
削除/addressbook/delete/:idGET連絡先を削除し、一覧に戻ります。

目次

  1. MongoDBのインストール
  2. Expressのインストールと雛形作成
  3. モデルの作成
  4. コントローラの作成
  5. ビューの作成

MongoDBをダウンロードしてインストールします。

$ curl -O http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.0.2.tgz .
$ rm mongodb-osx-x86_64-1.6.5.tgz 
$ tar -xzvf mongodb-osx-x86_64-2.0.2.tgz 
x mongodb-osx-x86_64-2.0.2/
x mongodb-osx-x86_64-2.0.2/bin/
x mongodb-osx-x86_64-2.0.2/bin/bsondump
x mongodb-osx-x86_64-2.0.2/bin/mongo
x mongodb-osx-x86_64-2.0.2/bin/mongod
x mongodb-osx-x86_64-2.0.2/bin/mongodump
x mongodb-osx-x86_64-2.0.2/bin/mongoexport
x mongodb-osx-x86_64-2.0.2/bin/mongofiles
x mongodb-osx-x86_64-2.0.2/bin/mongoimport
x mongodb-osx-x86_64-2.0.2/bin/mongorestore
x mongodb-osx-x86_64-2.0.2/bin/mongos
x mongodb-osx-x86_64-2.0.2/bin/mongosniff
x mongodb-osx-x86_64-2.0.2/bin/mongostat
x mongodb-osx-x86_64-2.0.2/bin/mongotop
x mongodb-osx-x86_64-2.0.2/GNU-AGPL-3.0
x mongodb-osx-x86_64-2.0.2/README
x mongodb-osx-x86_64-2.0.2/THIRD-PARTY-NOTICES
$ sudo mv mongodb-osx-x86_64-2.0.2/bin/* /usr/local/bin/
Password:
$ rm -fr mongodb-osx-x86_64-2.0.2 mongodb-osx-x86_64-2.0.2.tgz 

データ保存用のディレクトリを作成します。

$ mkdir ~/Library/MongoDB_Data

起動して動作を確認します。(--dbpathは絶対パスです。)

$ mongod --dbpath=/Users/inouetomoyuki/Library/MongoDB_Data/ &
[1] 86938
$ Sat Jan 14 16:21:40 [initandlisten] MongoDB starting : pid=86938 port=27017 dbpath=/Users/inouetomoyuki/Library/MongoDB_Data/ 64-bit host=imonshin.globals.jp
Sat Jan 14 16:21:40 [initandlisten] db version v2.0.2, pdfile version 4.5
Sat Jan 14 16:21:40 [initandlisten] git version: 514b122d308928517f5841888ceaa4246a7f18e3
Sat Jan 14 16:21:40 [initandlisten] build info: Darwin erh2.10gen.cc 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008; root:xnu-1228.9.59~1/RELEASE_I386 i386 BOOST_LIB_VERSION=1_40
Sat Jan 14 16:21:40 [initandlisten] options: { dbpath: "/Users/inouetomoyuki/Library/MongoDB_Data/" }
Sat Jan 14 16:21:40 [initandlisten] journal dir=/Users/inouetomoyuki/Library/MongoDB_Data/journal
Sat Jan 14 16:21:40 [initandlisten] recover begin
Sat Jan 14 16:21:40 [initandlisten] info no lsn file in journal/ directory
Sat Jan 14 16:21:40 [initandlisten] recover lsn: 0
Sat Jan 14 16:21:40 [initandlisten] recover /Users/inouetomoyuki/Library/MongoDB_Data/journal/j._0
Sat Jan 14 16:21:40 [initandlisten] recover cleaning up
Sat Jan 14 16:21:40 [initandlisten] removeJournalFiles
Sat Jan 14 16:21:40 [initandlisten] recover done
Sat Jan 14 16:21:40 [websvr] admin web console waiting for connections on port 28017
Sat Jan 14 16:21:40 [initandlisten] waiting for connections on port 27017

別のターミナルを開いて、MongoDBクライアントを起動してみます。

$ mongo
MongoDB shell version: 2.0.2
connecting to: test
Sat Jan 14 16:23:08 [initandlisten] connection accepted from 127.0.0.1:49329 #1
>

MongoDBのコンソールに入りました。起動しているようです。show dbsでデータベースを一覧します。

> show dbs
local (empty)

データベースはまだ存在しません。以下のようなコマンドを打ってみます。

> db.addressbook.save({'name':'Miku Hatsune'});
> db.addressbook.find();
{ "_id" : ObjectId("4f1130033a59d9bef8402fc7"), "name" : "Miku Hatsune" }
> 

コレクションaddressbookにデータが登録されています。

> show dbs;
local (empty)
test 0.203125GB
> 

testというデータベースができています。

exitコマンドでターミナルに戻ります。mongodは起動したままにして、アプリの開発に進みます。(mongodを終了するにはkill -9コマンドを使用します)


Expressとmongooseのインストール

$ sudo npm install -g express
$ express addressbook
$ cd addressbook && npm install
$ npm install mongoose
$ mkdir models
$


モデルContactの作成

models/contact.jsというファイル名でContact(連絡先)のモデルを作成します。

models/contact.js

var mongo = require('mongoose');
mongo.connect('mongodb://localhost/addressbook');

var Schema = mongo.Schema;

var Contact = mongo.model('contacts', new Schema({
    name: String,
    address: String,
    createAt: {type: Date, default: Date.now}
    })  
);

module.exports = Contact;

app.jsにコードを追加してmodels/contactを使えるようにします。

app.js

var express = require('express')
  , routes = require('./routes')
  , contact = require('./models/contact');


コントローラの作成

app.jsに記述していきます。アクション毎に書いていくのが良いのですが、ここでは一気に掲載します。

app.js

// ホーム
app.get('/', function(req, res) {
   res.redirect('/addressbook/list'); 
});

// 一覧表示
app.get('/addressbook/list', function(req, res) {
    contact.find({}, function(err, contacts) {
        if(err) throw err;
        res.render('list', {title:'Address Book', contacts:contacts});
    }); 
});

// 詳細表示
app.get('/addressbook/show/:id', function(req, res) {
    contact.findOne({_id:req.param('id')}, function(err, contact) {
        if(err) throw err;
        res.render('show', {title:'Contact', contact:contact});
    }); 
});

// 編集表示
app.get('/addressbook/edit/:id', function(req, res) {
    contact.findOne({_id:req.param('id')}, function(err, contact) {
        if(err) throw err;
        res.render('edit', {title:'Contact(Edit)', contact:contact});
    }); 
});

// 新規作成表示
app.get('/addressbook/new', function(req, res) {
    res.render('new', {title:'Contact(New)'});
});

// 更新アクション
app.post('/addressbook/update/:id', function(req, res) {
    contact.findById(req.param('id'), function(err, contact) {
        if(!contact)
            throw err;
        else {
            contact.name = req.param('name');
            contact.address = req.param('address');
            contact.save(function(err) {
                if(err)
                    throw err;
                else
                    res.redirect('/addressbook/show/' contact._id);
            });
        }
    });
});

// 追加アクション
app.post('/addressbook/insert', function(req, res) {
    var con = new contact();
    con.name = req.param('name');
    con.address = req.param('address');
    con.save(function(err) {
        if(err) throw err;
        res.redirect('/addressbook/list');
    });
});

// 削除アクション
app.get('/addressbook/delete/:id', function(req, res) {
    contact.remove({_id:req.param('id')}, function(err) {
        if(err) throw err;
        res.redirect('/addressbook/list');
    });
});



ビューの作成

views/list.jade

table(border='1')
    - for (var i=0; i<contacts.length; i  )
        tr
            td: a(href='/addressbook/show/'   contacts[i]._id)= contacts[i].name
            td= contacts[i].address
p
    a(href='/addressbook/new')
        新規作成

views/show.jade

h2 氏名
p= contact.name
h2 住所
p= contact.address
p
    a(href='/addressbook/edit/'   contact._id)
        編集
p
    a(href='/addressbook/delete/'   contact._id)
        削除

views/edit.jade

form(action='/addressbook/update/'   contact._id, method='post')
    h2 氏名
    input#name(name='name', type='text', value=contact.name)
    h2 住所
    input#address(name='address', type='text', value=contact.address)
    p
        input#submit(type='submit', value='保存')

views/new.jade

form(action='/addressbook/insert', method='post')
    h2 氏名
    input#name(name='name', type='text')
    h2 住所
    input#address(name='address', type='text')
    input#submit(type='submit', value='保存')

動作確認

http://127.0.0.1:3000 にアクセスして動作を確認します。

一覧画面

新規作成画面

一覧画面(追加後)

詳細画面

編集画面

1 件のコメント:

Unknown さんのコメント...

ソースを書いていただいてるので分かりやすいです。助かりました。
(なぜか'+'がソース上消えています。)