satococoa's blog

Web や iOS アプリを作るエンジニアの日記です

NodeでMongoDBをいじってみた

Node(Node.js)とMongoDBは相性がいいらしいので、試してみました。

とりあえず今回やってみたのはWebフレームワークにexpressを使い、

  1. InstagramのPopularを取ってきて
  2. それをMongoDBにそのまま突っ込んで
  3. あとはその内容を表示するだけ

という簡単なプログラムです。

ローカルだけではなく、サーバーはNodeのPaaSであるJoyent Node(no.de)にも試しにデプロイしてみました。
no.deはてっきりherokuのようなものだと思っていたのですが、SSHでログインしたりMongoDBをインストールしたり、なんてこともできるようです。
実際、今回のサンプルもno.de上にMongoDBをインストールして動かしてみました。

ごめんなさい、no.deの登録とかデプロイの仕方とかは省きます。

ライブラリのインストール

必要なライブラリをインストールします。

(no.deで公開する場合は、SSHでログインして同じように実行する必要があるのかな。
それともライブラリも./lib/あたりに置いて一緒にgit pushしちゃう方がいいのか、そのあたりの作法がわかりません。
今回はSSHでログインしてnpm installしました。)

($ brew install mongodb # Macでbrewな人はこれでMongoDBが入ります。)
$ npm install jade express instagram mongodb

ひな形の生成

まずはexpressコマンドで基本となるコードを生成します。

$ express testapp

メインになるスクリプトはapp.jsというファイル名なのですが、no.deにアップしたときにserver.jsというファイルじゃないと自動的に起動しないみたいなので、server.jsにリネームしました。

express?

expressはRubySinatraっぽいフレームワークです。
Sinatraで言う以下にあたるのが、

get '/' do
  # do something...
end

expressではこうです。

app.get('/', function(req, res){
  // do something...
});

今話題のCoffeeScriptで書くともっとSinatraに近くなると思いますが、
それをno.de上で動かすやり方が分からなかったのでとりあえずJavaScriptで書いています。

今回書いたコード(一部)

MongoDBとやり取りするコードは以下のようになりました。
どんどんコールバックでコードが右に伸びてしまいます。もっとかっこいい書き方をぜひ覚えたいところ。

server.js
/**
 * Module dependencies.
 */

var express = require('express'),
    instagram = require('instagram').createClient(
      'Your-Client-Id', 'Your-Client-Secret'),
    Db = require('mongodb').Db,
    Server = require('mongodb').Server;

var app = module.exports = express.createServer();
var client = new Db('popular', new Server('127.0.0.1', 27017, {}));

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 
});

app.configure('production', function(){
  app.use(express.errorHandler()); 
});

// Routes

app.get('/', function(req, res){
  client.open(function(err, p_client){
    client.collection('images', function(err, collection){
      collection.find({}, {limit: 10}).toArray(function(err, images){
        res.render('index', {
          title: 'index',
          images: images
        });
      });
    });
  });
});

app.get('/popular', function(req, res){
  instagram.media.popular(function(images, error) {
    client.open(function(err, p_client){
      client.collection('images', function(err, collection){
        collection.remove();
        for (var i=0, l=images.length; i < l; i++) {
          collection.insert(images[i]);
        }
        res.redirect('/');
      });
    });
  });
});

// Only listen on $ node app.js

if (!module.parent) {
  app.listen(process.env.PORT || 3000);
}

最低限のやり方はなんとなくわかったので、実際にひとつアプリを作ってみています。
せっかくなのでCoffeeScriptで書きたいのでもうちょっと調べてみたいと思います。