マニュアル
PHP Manual

問い合わせ

問い合わせのスレーブへの分散

注意: 1.1.0+

» レプリカセット とバージョン 1.1.0 以降のドライバを使っている場合、 ドライバは読み込みを自動的にスレーブにまわします。 これは以前のバージョンのドライバにはなかった挙動で、"通常の" マスタ-スレーブでは 使えません

デフォルトでは、ドライバはすべての問い合わせをマスタに送信します。 "slaveOkay" オプションを設定すると、ドライバはすべての問い合わせを (もし可能なら) プライマリ以外のサーバーに送信します。 "slaveOkay" オプションは、 接続データベースコレクション および カーソル のすべてのレベルで設定できます。各クラスは上位の "slaveOkay" 設定を継承するので、たとえば

<?php

$db
->setSlaveOkay(true);
$c $db->myCollection;

$cursor $c->find();

?>

のようにすると、この問い合わせはスレーブに対して実行されます (コレクションがデータベースから "slaveOkay" の設定を継承し、カーソルはコレクションからその設定を継承します)。

スレーブはどのように選ばれるか

Mongo インスタンスは、 利用可能なスレーブの中から、ping の所要時間が最も短いものを自分のスレーブとして選択します。 つまり、PHP クライアントがヨーロッパとオーストラリアにあって それぞれのデータセンターにひとつずつセカンダリがあるとすると、 このようにすることができます。

<?php

// P はプライマリです

// オーストラリアのクライアント
$m1 = new Mongo("mongodb://P", array("replicaSet" => true));
$m1->foo->bar->find()->slaveOkay()->getNext();
echo 
"m1 のスレーブは ".$m1->getSlave()."\n";

// ヨーロッパのクライアント
$m2 = new Mongo("mongodb://P", array("replicaSet" => true));
$m2->foo->bar->find()->slaveOkay()->getNext();
echo 
"m2 のスレーブは ".$m2->getSlave()."\n";

?>

を試すと、おそらくこのような結果となります。


m1 のスレーブは australianHost
m2 のスレーブは europeanHost

クエリを実行してからでないとスレーブの選択が行われないことに注意しましょう。 スレーブの選択は、必要になった時点でドライバが行います。 まだスレーブを使っていない場合、Mongo::getSlave()NULL を返します。

セットのメンバーの現在の状態がどうなっているかを知るには、 Mongo::getHosts() を実行します。

読み込み可能な非プライマリサーバーがない場合は、 (たとえ "slaveOkay" が設定されていても) ドライバはプライマリから読み込みを行います。 あるサーバーが読み込み可能であると判定される条件は、その state が 2 (SECONDARY) かつ health が 1 であることです。 これらをチェックするには Mongo::getHosts() を使います。

あまり関わるべきではないところに首を突っ込んで楽しみたいのなら、 Mongo::switchSlave() をコールして別のスレーブを使わせることもできます。 これは、ランダムに新しいスレーブを選んでそれを使います。 自分が何をしているのかをしっかり把握しているのでない限り、これを使ってはいけません。

その他の注意点

書き込みは、常にプライマリに送られます。データベースコマンドについても、 たとえ読み込み専用のコマンドであっても常にプライマリに送られます。

スレーブの health と state は、5 秒おき あるいは次の操作の 5 秒前にチェックされます。 ドライバがサーバーに到達できずに何か問題が発生したときは、同時に設定の再チェックも行います。

非プライマリサーバーは、操作時はプライマリの背後に隠れています。 そのため、最新でないデータを受け取っても大丈夫なようにアプリケーション側で対応しなければなりません (あるいは、すべての書き込みで w を使わなければなりません)。

_id による問い合わせ

追加されたすべてのオブジェクトには、一意な _id フィールドが自動的に付加されます。 これは、問い合わせで使うフィールドとして便利です。

今追加したばかりのドキュメントを探すことを考えてみましょう。 追加するとドキュメントに _id フィールドができるので、それを問い合わせればいいのです。

<?php

$person 
= array("name" => "joe");

$people->insert($person);

// $joe には _id フィールドがあります
$joe $people->findOne(array("_id" => $person['_id']));

?>

ユーザーが別途指定しない限り、_id フィールドは MongoId となります。ありがちな間違いは、 文字列を MongoId とマッチさせようとすることです。 文字列とは別の型であり、そのままではマッチしないことを覚えておきましょう。 これは、文字列 "array()" と空の配列が別のものであるというのと同じことです。 次の例を参照ください。

<?php

$person 
= array("name" => "joe");

$people->insert($person);

// _id を文字列に変換します
$pid $person['_id'] . "";

// 失敗 - $pid は文字列であり、MongoId ではありません
$joe $people->findOne(array("_id" => $pid));

?>

配列

配列には特殊な点がいくつかあります。 まず、MongoDB が扱う配列には二種類あります。 "普通の" 配列と連想配列です。連想配列には、任意の型のキーと値を組み合わせることができます。 "普通の" 配列は、0 から始まってひとつずつ増えていく数値のインデックスに それぞれ要素を関連づけます。 これらは、ほぼ PHP の配列や連想配列と同じようなものです。

たとえば、受賞の一覧をドキュメントに保存するときには次のようにできます。

<?php

$collection
->save(array("awards" => array("gold""silver""bronze")));

?>

問い合わせでは、配列の要素も探すことができます。 指定した値が配列の要素に含まれるすべてのドキュメントを探すことを考えましょう。 たとえば、受賞 (awards) に金賞 (gold) が含まれる次のようなドキュメントです。

{ "_id" : ObjectId("4b06c282edb87a281e09dad9"), "awards" : ["gold", "silver", "bronze"]}

これは、単純なクエリで問い合わせることができます。"awards" が配列であるということを気にせず、次のようにすればいいのです。

<?php

  $cursor 
$collection->find(array("awards" => "gold"));

?>

もう少し複雑なオブジェクトを考えてみましょう。 配列の各要素のオブジェクトになっている、次のような例だとどうでしょう。

{ 
     "_id" : ObjectId("4b06c282edb87a281e09dad9"), 
     "awards" : 
     [
        {
            "first place" : "gold"
        },
        {
            "second place" : "silver" 
        },
        {
            "third place" :  "bronze"
        }
     ]
}

このような場合でも、配列であることを特別視する必要はありません。 内部のオブジェクトへの問い合わせには、ドット記法が使えます。

<?php

$cursor 
$collection->find(array("awards.first place" => "gold"));

?>

フィールド名にスペースが含まれていてもかまわないことに注目しましょう (スペースを使わないにこしたことはありませんが、可読性を考慮しました)。

配列を使って、取り得る値を複数指定した問い合わせを行うこともできます。 "gold" あるいは "copper" を含むドキュメントを探すには、このようにします。

<?php

$cursor 
$collection->find(array("awards" => array('$in' => array("gold""copper"))));

?>

マニュアル
PHP Manual