Asial Blog

Recruit! Asialで一緒に働きませんか?

symfonyでMongoDBを使ってみました

カテゴリ :
バックエンド(プログラミング)
タグ :
Tech
DB
symfony
こんにちは。笹亀です。

最近でも無いですが、なにかと注目を浴び続けているのがkey-valueストアです。TokyoTyrant, kumofs, ROMA, Flareなど種類も豊富で使用する用途によって使い分けするのがよいです。そんな中で自分がご紹介したいのはMongoDBです。

MongoDBはドキュメント指向データベースでNoSQLです。ご紹介理由としてはRDBMSから入るkey-valueストアとしてとてもわかりやすいからです。後はサポート言語が大量にあってWEBアプリケーションとして使用するのにとても相性がよいことです。
 ※PHP、Python、Ruby、Perlなどなど

その他にたくさんの特徴があります。詳細については、下記のドキュメントにてご確認ください。
http://www.mongodb.org/display/DOCSJP/Home
 ※日本人なら日本語のドキュメントに限ります(一部英語のままらしい)

まずはインストールしてみます。下記から自分の環境にあったものをダウンロードします。
http://www.mongodb.org/display/DOCS/Downloads
自分の場合はMacの10.6なので下記のように取得します
  1. wget http://downloads.mongodb.org/osx/mongodb-osx-x86_64-1.4.1.tgz

解凍してコマンドなどを設置(コピー)します。
  1. tar zxvf mongodb-osx-x86_64-1.4.1.tgz
  2. cd mongodb-osx-x86_64-1.4.1
  3. sudo cp bin/* /usr/bin/
  4. sudo cp -r include/* /usr/include/
  5. sudo cp lib/libmongoclient.a /usr/lib/

mongoデーモンをデータの格納先を指定して起動します。
  1. mongod --dbpath ~/mongodb &

PHPからMongoDBを使えるようにします。
  1. pecl install mongo
  2. php.iniにextensionの箇所にmongo.soを追加する
  3. apacheを再起動。

phpinfoでMongoが設定が反映されているか確認しましょう。



以上でPHPでMongoDBが使えるところまでいけます。

symfony(PHP)で使用する方法を記載します。まずは接続情報を記載します。MongoDBはスケーラブルに対応しておりますので今回はMaster-Slaveの情報の両方を記載します

config/mongo/databases.yml
  1. all:
  2.   master:
  3.     param:
  4.       dsn:     localhost:27017
  5.       dbname:   test
  6.   slave:
  7.     param:
  8.       dsn:     localhost:27017
  9.       dbname:   test

次にsymfonyでMongoへ登録、取得(件数のみ)するためのクラスを作成します。

lib/MongoKeyValue.class.php
  1. <?php
  2. class MongoKeyValue 
  3. {
  4.   protected $connection_master = null;
  5.   protected $connection_slave = null;
  6.   protected $table_name = null;
  7.   
  8.   /**
  9.    * コンストラクト
  10.    * 
  11.    * @param string $table_name
  12.    * @return MongoKeyValue
  13.    */
  14.   public function _construct($table_name = '') {
  15.     $this->table_name = $table_name;
  16.     
  17.     //コネクション情報をセット(Master&Slave
  18.     $file = sfConfig::get('sf_config_dir').'/mongo/databases.yml';
  19.     if (file_exists($file)) {
  20.       $config = sfYaml::load($file);
  21.     } else {
  22.       throw new InvalidArgumentException('not mongo databases.yml');
  23.     }
  24.  
  25.     $getDb = function ($name) use ($config)
  26.     {
  27.       $param = $config['all'][$name]['param'];
  28.       $mongo = new Mongo($param['dsn']);
  29.       return $mongo->selectDB($param['dbname']);
  30.     };
  31.     
  32.     //コネクションをセット
  33.     $this->connection_master = $getDb('master');
  34.     $this->connection_slave  = $getDb('slave');
  35.   }
  36.  
  37.   public function getMasterCollection()  
  38.   {
  39.     return $this->connection_master->selectCollection($this->table_name);
  40.   }
  41.   public function getSlaveCollection()  
  42.   {
  43.     return $this->connection_slave->selectCollection($this->table_name);
  44.   }
  45.  
  46.   /**
  47.    * データインサート処理
  48.    * 
  49.    * @param array $params
  50.    * @return boolean
  51.    */
  52.   public function setKeyValue($params) {
  53.     if (is_array($params)) {
  54.       $result = $this->getMasterCollection()->insert($params);
  55.       return $result;
  56.     } else {
  57.       return false;
  58.     }
  59.   }
  60.  
  61.   /**
  62.    * 条件を設定してデータ件数を取得する
  63.    * 
  64.    * @param array $params 取得条件
  65.    * @return integer
  66.    */
  67.   public function getKeyValue($params) {
  68.     if (is_array($params)) {
  69.       return $this->getSlaveCollection()->count($params);
  70.     } else {
  71.       return false;
  72.     }
  73.   }
  74.   
  75. }


準備ができたら実際にactionに記載して登録処理と件数を取得するものを作成して確認してみましょう。
  1. public function executeTest() {
  2.     $mongo = new MongoKeyValue('test_table');
  3.     $params['class_id'] = "1";
  4.     $params['name']     = '笹亀弘';
  5.     $mongo->setKeyValue($params);
  6.     
  7.     $params1['class_id'] = "1";
  8.     $params1['name']     = 'ささがめひろし';
  9.     $mongo->setKeyValue($params1);
  10.     
  11.     $params2['class_id'] = "2";
  12.     $params2['name']     = 'ささがめひろし';
  13.     $mongo->setKeyValue($params2);
  14.     
  15.     usleep(1000000);
  16.     
  17.     $params3['class_id'] = "1";
  18.     print $mongo->getKeyValue($params3);
  19.     exit;
  20.   }


usleepしている箇所についてですが、Mongoで連続で登録してカウントの処理をするときに、Lock処理が入りませんので、登録処理を完了する前に件数を取得する部分が発行してしまい件数が合わない場合があります。そのためにsleepで処理を止めています。

カウント取得しているものには条件を指定します。ここではカウント取得条件はclass_idが1である件数を取得しています。また、MongoDBはPHPとは違い数値と文字列の数値を区別する必要がありますので、カウントを取得する際などには注意が必要です。
  1.     $params3['class_id'] = "1";
  2.     print $mongo->getKeyValue($params3);
  3.   結果: 2
  4.     $params4['class_id'] = 1;
  5.     print $mongo->getKeyValue($params4);
  6.   結果: 0


MySQLなどのようにMongoにもコマンドで実行して値を確認する方法もあります。使用するコマンドは「mongo」コマンドから値を操作することができます。


mongoの基本的なコマンドしか実行しておりませんので、その他にどういったものがあるかはコマンドのhelpで確認するか、ドキュメントよりご確認いただけたらと思います。


symfonyでMongoクラスを作成しましたが、こちらには登録処理とカウントする処理しかありません。その他にも削除する処理やデータを取得するものを拡張していただければ自由にMongoDBの値を扱うことが可能になります。