nazolabo

フリーランスのWebエンジニアが近況や思ったことを発信しています。

第9回 LOCAL PHP部勉強会

4/24に札幌でPHP勉強会をします。

日時 2010年4月24日(土) 14:00〜16:30
場所 札幌産業振興センター セミナールーム2
費用 参加費(会場代、おやつ代) 1人500円
懇親会 終了後は毎回恒例の懇親会を予定しております。

参加登録は http://atnd.org/events/4056 からどうぞ。
ちなみにぼくはlithiumネタを喋ることになってますが、lithiumまだ使ったことありません…

LDD'10WinterのMongoDBの資料

2010/02/13に札幌で開催された[LOCAL DEVELOPER DAY '10 /Winter:title=http://www.local.or.jp/?LDD/LDD10Winter](LDD'10Winter)で、MongoDBの話をしてきました。

今回はMongoDBについてを一通り話すつもりだったのですが、一通りすぎて全然時間が足りませんでした。ごめんなさい。
あと、既存の概念ではないものを説明するのは難しいです。喋りながら全然伝わった感じがありませんでした。MapReduceとか捨ててそっちの説明に重点を置いたほうがいい気がしました。
MongoDBに関しては、機会があればまた話したいと思います。

LOCAL DEVELOPER DAY '10 /Winterが開催されます

2/13に、札幌でLOCAL DEVELOPER DAY '10 /Winter(LDD)が開催されます。

日時 2010/2/13(土) 12:45〜18:35
会場 札幌市産業振興センター セミナールームA
参加費 無料
懇親会 http://atnd.org/events/2843(2/5締切)
公式タグ ldd10winter
公式ハッシュタグ #ldd10w
詳細 http://www.local.or.jp/?LDD%2FLDD10Winter

LT発表者も募集中です!道内の技術者の人は是非参加してください!
ちなみに去年はこんな感じでした。

PHPでMongoDBを使ってみる その2

http://www.nyphp.org/PHP-Presentations/145_Recovering-Mongos-MongoDB-PHP
これが参考になる

=以外の条件

<?php

$mongo = new Mongo();

$col = $mongo->selectDB( "foo" )->selectCollection( "bar" );

$data = array("name" => "foo", "num" => 1);
$col->insert( $data );
$data = array("name" => "bar", "num" => 2);
$col->insert( $data );
$data = array("name" => "baz", "num" => 3);
$col->insert( $data );

$cursor = $col->find(array('num' => array('$gt' => 1)));
foreach ($cursor as $id =>$obj) {
        var_dump( $obj );
}

$gtとか$ltとかで条件指定するらしい、""で囲むとPHPの変数扱いされるので''で。
ちなみにこの$はphp.iniのmongo.cmdで変更できる。

$gt >
$lt
$gte >=
$lte <=
$ne !=
$in SQLのINと同じ
$nin NOT IN
$mod array(x, y)と指定した場合、対象をxで割った余りが1かどうか
$all 集合を全て含むかどうか
$size 要素の数
$exists フィールドが存在するかどうか(true/false)

詳しくは
http://www.mongodb.org/display/DOCS/Advanced+Queries

文字列の部分一致

正規表現が使える

<?php
//このへんまで上のと同じ

$cursor = $col->find(array('name' => new MongoRegex('/ba/i')));
foreach ($cursor as $id =>$obj) {
        var_dump( $obj );
}

MongoRegexオブジェクトを作らないといけないのがちょっと面倒(言語によってはそのままいけるらしい)

SQLっぽい条件指定

SQLインジェクションの恐怖再び

$cursor = $col->find(array('$where' => 'this.num > 1'));

this.何とかで、自分の値を取れるので、this.x + this.y > 1とかもできる。

JavaScript条件

MongoDBはJavaScriptエンジンを内蔵しているので、

$cursor = $col->find(array('$where' => 'this.num > Math.abs(-1)'));

こういうことができる。
単にJavaScriptを実行してほしいだけなら

<?php
$mongo = new Mongo();
$db = $mongo->selectDB( "foo" );
$code = new MongoCode("function() { return 'hello'; }");
$ret = $db->execute($code);
var_dump($ret);

これで、array('retval' => 'hello', 'ok' => 1)が返ってくる。
JSに対してPHPから引数を与えたい場合は、

<?php

$mongo = new Mongo();
$db = $mongo->selectDB( "foo" );
$code = new MongoCode("function() { return x + 1; }", array("x" => 1));
$ret = $db->execute($code);
var_dump($ret);

深い階層の条件指定

<?php

$mongo = new Mongo();

$col = $mongo->selectDB( "foo" )->selectCollection( "bar" );

$data = array("name" => "foo", "data" => array('a' => 1, 'b' => 10));
$col->insert( $data );
$data = array("name" => "bar", "data" => array('a' => 2, 'b' => 20));
$col->insert( $data );
$data = array("name" => "baz", "data" => array('a' => 3, 'b' => 30));
$col->insert( $data );

$cursor = $col->find(array('data.a' => 1));
foreach ($cursor as $id =>$obj) {
        var_dump( $obj );
}

ドットで繋ぐ。

ページング的な処理

LIMITとOFFSET的な(上の資料からコピペ)

$page_num= 3;
$results_per_page= 10;
$cursor = $results->find()
                  ->sort(array("ts" => -1))
                  ->skip($page_num * $results_per_page)
                  ->limit($results_per_page);

skipがoffset、limitはlimitで。

おまけ

MongoDBをO/Rマッパ的に使うライブラリMorph
http://code.google.com/p/mongodb-morph/
なんかメリット殺してるような気がしなくも…。でも楽かもしれない

PHPでMongoDBを使ってみる

5ヶ月ぶりの更新とかどういうことなの…

MongoDBのインストール

バイナリが配布されているのでそれを使う
http://www.mongodb.org/
自分のプラットフォーム用バイナリを落として、/opt/mongoに入れると仮定。変なプラットフォームの人はgithubから拾ってくる。
あとデータフォルダがデフォルトで/data/dbとかという変なパスなので作る

sudo mkdir -p /data/db

PHP拡張を入れる

sudo pecl install mongo

あとphp.iniにextension=mongo.soを書く

起動

普通に実行してもいいけど
http://gist.github.com/232227
このへんにinitスクリプトがあるので拾ってきてパスを書き換える

使い方

ここから本編
というかチュートリアルがあるからそれを参考にする
http://www.mongodb.org/display/DOCS/PHP+Tutorial

DBに接続
$mongo = new Mongo();

外部に接続する場合は

$mongo = new Mongo("example.com:65432");
データベースを取得

RDBのデータベースと同じ単位だと思われるデータベースへの接続ハンドラ(?)を取得

$db = $mongo->selectDB( "dbname" );

あ、CREATE DATABASE的なものはいらないです。

コレクションを取得

RDBのテーブルと同じ単位だと思われるコレクションへの接続ハンドラ(?)を取得
ハンドラというか何て呼ぶんだこれは

$col = $db->selectCollection( "collectionname" );

あ、CREATE TABLE的なものはいらないです。

コレクションにデータを入れる

いわゆるINSERT
テーブル定義なんてものはないよ!自由に入れれるよ!

$doc = array( "name" => "MongoDB",
   "type" => "database",
   "count" => 1,
   "info" => (object)array( "x" => 203,
       "y" => 102),
   "versions" => array("0.9.7", "0.9.8", "0.9.9")
);
$col->insert( $doc );

こんな感じで、自由に定義した配列を入れれる。勝手に拡張もできる。
ちなみにinsertすると、内部ID保持用に_idというキーが自動的に$docに入る。あとでUPDATEとかに使う。

1項目取得

findOneというそのままな

$obj = $col->findOne();
var_dump( $obj );

条件指定する場合は

$obj = $col->findOne(array("name"=>"MongoDB"));
var_dump( $obj );

ない場合はnullを返す

件数取得
$col->count();
複数項目取得

findでできる

$cursor = $col->find();
foreach ($cursor as $id =>$obj) {
  var_dump( $obj );
}

findが返すのはカーソルなので、foreachで回して処理する。もちろんfindに条件を指定することもできる。
ちなみに

$cursor->count();

で、問い合わせ結果の件数を取得できる。
ORDER BY的なことをしたい場合は、

$cursor->sort(array('name'=>1));

とかする。-1にすると逆順になる。この「1で昇順、-1で降順」は他でも出てくる。

インデックスの作成
$col->ensureIndex( array( "name" => 1 ) );

というわけで出てきました。
複合インデックスの場合は

$col->ensureIndex( array( "name" => 1 , "count" => -1 ) );

みたいに。
第二引数をTRUEにするとunique制約になる。

データの更新
$col->update(array("name" => "MongoDB"), $newobj);

第三引数にTRUEを指定すると、対象が見つからない場合にINSERTしてくれる。
取得してきたものをそのまま更新したい場合は

$obj = $col->findOne();
$obj["name"] = "nazo";
$col->save($obj);
削除

DBの削除

$db->drop();

Collectionの削除

$col->drop();

条件指定でデータを削除

$col->remove(array("name" => "MongoDB"));

条件指定でデータを削除(1つだけ)

$col->remove(array("name" => "MongoDB"), true);

findしたものを削除

$obj = $col->findOne();
$col->remove($obj);

詳しいAPIドキュメント

なんと公式にあるよ!まあPECLだから当たり前?だけど!
http://jp.php.net/mongo

twitterの発言の勢いを表示するUserScript

アドオンとかで、その人がどれだけ喋ってるかとか、いわゆる「勢い」がどれぐらいか視覚的に分かるものをフォロワ一覧もしくはそれぞれのHomeとかでざっと見たりとかできたりしたら便利そうだなあ。アイコンをよくしゃべってる人から順に赤-橙-黄-緑-青-紫-黒ってborderつけたり

https://twitter.com/waka_/status/2322401195

それグリモンでできるんじゃね?ということで作ってみた!
http://nazone.info/gm/timelinepower.user.js

インストールして、各ユーザーのHomeを開くと、名前の上のほうにカラーバーが表示されます。
赤いほうが最近活発に発言しています。

follow前に「この人最近twitter使ってるのかな…」と確認する時にでもお使い下さい。

既知の不具合