If you are getting "writing more" shown at random places on the screen, it's a MongoDB connector bug in 1.0.5.
Bug report: http://jira.mongodb.org/browse/PHP-91
Update to the latest connector driver and it should go away.
チュートリアル
導入
これは、10gen がサポートする MongoDB 用 PHP ドライバです。
簡単なコード例をもとに、MongoDB への接続やドキュメントの追加、 ドキュメントの問い合わせ、問い合わせ結果の反復処理、 そして接続の切断の方法を示します。 各ステップの詳細については後に続くチュートリアルを参照ください。
<?php
// 接続
$m = new Mongo();
// データベースの選択
$db = $m->comedy;
// コレクション (リレーショナルデータベースのテーブルみたいなもの) の選択
$collection = $db->cartoons;
// レコードの追加
$obj = array( "title" => "Calvin and Hobbes", "author" => "Bill Watterson" );
$collection->insert($obj);
// 構造が異なる別のレコードの追加
$obj = array( "title" => "XKCD", "online" => true );
$collection->insert($obj);
// コレクション内の全件の検索
$cursor = $collection->find();
// 結果の反復処理
foreach ($cursor as $obj) {
echo $obj["title"] . "\n";
}
?>
この出力は、次のようになります。
Calvin and Hobbes XKCD
接続の作成
データベースサーバーに接続するには、次のいずれかの方法を使います。
<?php
$connection = new Mongo(); // localhost:27017 に接続します
$connection = new Mongo( "example.com" ); // リモートホスト (デフォルトのポート: 27017) に接続します
$connection = new Mongo( "example.com:65432" ); // リモートホストの指定したポートに接続します
?>
明示的にデータベースとの接続を切断する必要はありません。 $connection がスコープ外に抜けた時点で接続は自動的に閉じられ、 使っていたデータベースリソースもすべて開放されます。
参考
接続のページで、 さまざまな形式の接続を扱っています。
Mongo クラスや Mongo::__construct() の API ドキュメントには、 利用可能なすべてのオプションや多くのサンプルがあります。
データベースの取得
データベースを選択するには次のようにします。
<?php
$db = $connection->dbname;
?>
データベースを事前に作っておく必要はありません。 存在しないデータベースを選択すれば、新しいデータベースを作ることができます。
Typo には注意しましょう! 意図せずに新しいデータベースを作ってしまい、 エラーで悩まされる原因になります。
<?php
$db = $connection->mybiglongdbname;
// 何かをします
$db = $connection->mybiglongdbanme;
// これは別のデータベースに接続してしまいます!
?>
参考
MongoDB クラスの API ドキュメントに、 データベースオブジェクトに関する詳細な情報があります。
コレクションの取得
コレクションの取得は、データベースの取得と同じ構文で行えます。
<?php
$db = $connection->baz;
$collection = $db->foobar;
// あるいは、もうすこし簡潔に
$collection = $connection->baz->foobar;
?>
リレーショナルデータベースになじみのある人にとっては、 コレクションとはテーブルに似たものだと考えればわかりやすいでしょう。
参考
MongoCollection クラスの API ドキュメントに、 コレクションオブジェクトに関する詳細な情報があります。
ドキュメントの追加
連想配列は、データベース内のコレクションに保存できる基本的なオブジェクトです。 何らかの "ドキュメント" はこのような形式になります。
<?php
$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")
);
?>
配列やオブジェクトをネストできることに注目しましょう。
ドキュメントを追加するには MongoCollection::insert() を使います。
<?php
$collection->insert( $doc );
?>
参考
MongoCollection::insert() の API ドキュメントに、 データの追加に関する詳細な情報があります。
MongoCollection::findOne() によるドキュメントの検索
先ほどの例で追加したドキュメントを表示するには、 シンプルに MongoCollection::findOne() を実行してコレクションからドキュメントをひとつ取得します。 このメソッドは、クエリにマッチするドキュメントがひとつだけしかないときや 一件の結果にだけしか興味がない場合に便利です。
<?php
$obj = $collection->findOne();
var_dump( $obj );
?>
結果は、このようになります。
array(6) {
["_id"]=>
object(MongoId)#8 (1) {
["$id"]=>
string(24) "4e2995576803fab768000000"
}
["name"]=>
string(7) "MongoDB"
["type"]=>
string(8) "database"
["count"]=>
int(1)
["info"]=>
array(2) {
["x"]=>
int(203)
["y"]=>
int(102)
}
["versions"]=>
array(3) {
[0]=>
string(5) "0.9.7"
[1]=>
string(5) "0.9.8"
[2]=>
string(5) "0.9.9"
}
}
_id フィールドが 自動的にドキュメントに追加されていることに注目しましょう。 _id は、いわゆる「主キー」フィールドです。 ドキュメントにキーがなければ、ドライバが自動的に追加します。
自前で _id フィールドを指定する場合は、 コレクション内で一意になるようにしなければなりません。 例をごらんください。
<?php
$db->foo->insert(array("_id" => 1), array("safe" => true));
// これは例外が発生します
$db->foo->insert(array("_id" => 1), array("safe" => true));
// こちらは別のコレクションなので大丈夫です
$db->bar->insert(array("_id" => 1), array("safe" => true));
?>
これらの追加処理では、二番目の引数で配列 array("safe" => true) を渡していることに注目しましょう。 これは、追加時のオプションです。デフォルトでは、 ドライバは書き込み処理の応答を待ちません。そのため、ドライバが _id を取得できなくなります。 この操作が "安全な" 書き込みであると指定することで、 ドライバは書き込み操作の完了を待って書き込みが消えてしまわないようにします。 一般に、すべての書き込みには "safe" オプションを指定しておくべきです (先ほどの例で省略していたのは、コードをシンプルにするためです)。
参考
MongoCollection::findOne() に、 データの検索に関する詳細な情報があります。
MongoId には、一意な ID に関する詳細な説明があります。
書き込みのページでは、 安全な書き込みについてより詳しく扱っています。 MongoCollection::insert()、 MongoCollection::update() そして MongoCollection::remove() といった書き込み関数の使いかたもあります。
複数のドキュメントの追加
もう少し意味のある問い合わせをするために、複数のシンプルなドキュメントをコレクションに追加しましょう。 ドキュメントは array( "i" => value ); 形式で、これをループ内で処理します。
<?php
for($i=0; $i<100; $i++) {
$collection->insert( array( "i" => $i ) );
}
?>
先ほどと同じコレクションに、別のキーを持つ配列を追加していることに注目しましょう。 MongoDB が「スキーマフリー」であると言われるのは、こういう側面があるからです。
コレクション内のドキュメント数
これで 101 件のドキュメントを追加したことになります (先ほどのループで 100 件、そして最初の 1 件)。 本当にそうなっているか、MongoCollection::count() メソッドで確認してみましょう。
<?php
echo $collection->count();
?>
カーソルを使った全ドキュメントの取得
コレクション内のすべてのドキュメントを取得するには MongoCollection::find() を使います。 find() メソッドは MongoCursor オブジェクトを返し、 これを使うとクエリにマッチしたドキュメントすべてに対する反復処理ができるようになります。 では、すべてのドキュメントを取得して表示させてみましょう。
<?php
$cursor = $collection->find();
foreach ($cursor as $id => $value) {
echo "$id: ";
var_dump( $value );
}
?>
参考
MongoCollection::find() の API ドキュメントに、 データの検索に関する詳細な情報があります。
問い合わせの条件の設定
クエリを作って MongoCollection::find() メソッドに渡せば、 コレクション内のドキュメントのサブセットを取得することができます。 たとえば、"i" フィールドの値が 71 であるドキュメントを探したいときは、 このようにします。
<?php
$query = array( "i" => 71 );
$cursor = $collection->find( $query );
while( $cursor->hasNext() ) {
var_dump( $cursor->getNext() );
}
?>
そうすると、ひとつのドキュメントだけが表示されます。
array(2) {
["_id"]=>
object(MongoId)#6 (0) {
}
["i"]=>
int(71)
["_ns"]=>
"testCollection"
}
クエリによる複数ドキュメントの取得
クエリを使って、コレクションからドキュメントのセットを取得することができます。 たとえば、"i" > 50 であるすべてのドキュメントを取得したい場合は次のようにします。
<?php
$query = array( "i" => array( '$gt' => 50 ) ); // '$gt' と、シングルクォートで囲んでいることに注意しましょう
$cursor = $coll->find( $query );
while( $cursor->hasNext() ) {
var_dump( $cursor->getNext() );
}
?>
これは、i > 50 であるドキュメントをすべて表示します。 また、20 < i <= 30 のような範囲を指定することもできます。
<?php
$query = array( "i" => array( "\$gt" => 20, "\$lte" => 30 ) );
$cursor = $coll->find( $query );
while( $cursor->hasNext() ) {
var_dump( $cursor->getNext() );
}
?>
常に $ 記号をエスケープするか、あるいはシングルクォートを使うことを覚えておきましょう。 そうしないと、PHP はこれを変数 $gt と解釈してしまいます。
インデックスの作成
MongoDB はインデックスをサポートしています。コレクションにインデックスを追加するのは簡単です。 インデックスを作るには、対象となるフィールドと並び順を指定します。 並び順は、昇順 (1) あるいは降順 (-1) のいずれかです。 この例では、"i" フィールドの昇順でインデックスを作成しています。
<?php
$coll->ensureIndex( array( "i" => 1 ) ); // "i" にインデックスを作ります
$coll->ensureIndex( array( "i" => -1, "j" => 1 ) ); // "i" の降順、"j" の昇順でインデックスを作ります
?>
データが増えてもよいパフォーマンスを維持するためには、インデックスが不可欠です。 インデックスについてよくわからない場合は、MongoCollection::ensureIndex() のドキュメントと、本家の » インデックスに関するドキュメント を参照ください。
please note that if you need to re-index a numeric array after and unset by offset and preserve order array_merge with only one argument will output an array keyed sequentially
<?php
$arr = array(1,2,3,4,5);
unset($arr[2]);
var_dump($arr);
$arr = array_merge($arr);
var_dump($arr);
?>
--output--
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[3]=>
int(4)
[4]=>
int(5)
}
array(4) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(4)
[3]=>
int(5)
}
Make sure array keys consecutive before inserting. As of 1.0.6 driver, the following will end up as an object of key:value pairs, instead of an array, because it's trying to maintain the 0 and 2 keys:
$array = array('a', 'b', 'c');
unset($array[1]);
$document = array(
'embedded' => $array,
);
// assuming local
$mongo = new Mongo();
$mongo->test->test->insert($document);
mongodb result:
{ "_id" : ObjectId(...), "embedded" : { "0" : "a", "2" : "c" } }
This is bad if you plan on indexing the embedded property as an array because objects and arrays are indexed differently.
Whether the behaviour will change or not, this is logged here: http://jira.mongodb.org/browse/PHP-104
If you know about it, it's not major, just use a sort() before inserting, or use array_* methods to remove elements instead of unset() -- anything that will re-adjust keys.
