追尾可能 (tailable) カーソルの反復
Overview
ドライバーがクエリまたはコマンド(例: 集計 )、操作の結果は MongoDB\Driver\Cursor を介して返されます オブジェクト。カーソル クラスは PHP の イテレータ を実装します インターフェースにより、 で反復処理され、 イテラブルforeach
を操作する任意の PHP 関数とのインターフェースが可能になります 。他のデータベース ドライバーの結果オブジェクトと同様に、MongoDB のカーソルはフォワード反復のみをサポートしているため、書き換えたり、 foreach
で複数回使用したりすることはできません。
追尾可能 (tailable) カーソルは、クライアントが結果を読み取った後、使用可能なドキュメントを増やすまで待機できる MongoDB カーソルの特殊なタイプです。 これらのカーソルは、主にCapped コレクションとChange Streamsで使用されます。
通常のカーソルはforeach
を使用して 1 回反復できますが、そのアプローチは 追尾可能 (tailable) カーソルでは機能しません。 foreach
を追尾可能 (tailable) カーソルと併用する場合、初期結果セットの末尾に到達するとループは停止します。 2 つ目のforeach
を使用してカーソルの反復処理を続行しようとすると、PHP はカーソルを巻き戻すのを試みるため、例外がスローされます。 したがって、追尾可能 (tailable) カーソルから読み取るには、 イテレータ を直接使用する必要があります。 API。
注意
1.9.0拡張機能のバージョンext-mongodb
より前では、カーソル クラスは イテレータ を実装していません インターフェースを使用します。以下の メソッドを使用してカーソルを手動で反復処理するには、まず イテレータ イテレータでラップする必要があります。
通常のカーソルの手動反復処理
追尾可能 (tailable) カーソルが反復処理される方法を確認する前に、まず、 Iterator
メソッドが通常のカーソルとどのように相互作用するのかを調べます。
次の例では、5 つのレストランを検索し、 foreach
を使用して結果を表示しています。
$collection = (new MongoDB\Client)->test->restaurants; $cursor = $collection->find([], ['limit' => 5]); foreach ($cursor as $document) { var_dump($document); }
この例は非常に簡潔ですが、実際にはかなりの処理が行われています。 foreach
構築は、イテラブル(この場合は$cursor
)を巻き戻すことで開始されます。 次に、現在の位置が有効かどうかを確認します。 位置が無効な場合、ループは終了します。 それ以外の場合、現在のキーと値に応じてアクセスされ、ループ本体が実行されます。 ブレークし た場合 が発生しなかった場合、イテレータは次の位置に進み、制御は有効性チェックに戻り、ループが続行されます。
foreach
の内部動作により、前の例を変換して イテレータ メソッドを直接使用できるようになります。
$collection = (new MongoDB\Client)->test->restaurants; $cursor = $collection->find([], ['limit' => 5]); $cursor->rewind(); while ($cursor->valid()) { $document = $cursor->current(); var_dump($document); $cursor->next(); }
注意
while
ループが自然に終了した後に$cursor->next()
を呼び出すと、カーソル上のすべての結果が使い果たされたため、例外がスローされます。
foreach
この例の目的は、PHP の イテレータ を使用して、 と手動反復処理の機能同等性を示すことです。 API。通常のカーソルの場合、簡潔なforeach
ループではなく、結果を手動で反復処理する理由はほとんどありません。
追尾可能 (tailable) カーソルの反復処理
追尾可能 (tailable) カーソルの動作を示すには、「プロデューサー」と「コンシューマー」の 2 つのスクリプトが必要です。 プロデューサー スクリプトは、 MongoDB\Database::createCollection()
を使用して新しい Capped コレクションを作成し、1 秒ごとにそのコレクションに新しいドキュメントの挿入を続行します。
$database = (new MongoDB\Client)->test; $database->createCollection('capped', [ 'capped' => true, 'size' => 16777216, ]); $collection = $database->selectCollection('capped'); while (true) { $collection->insertOne(['createdAt' => new MongoDB\BSON\UTCDateTime()]); sleep(1); }
プロデューサー スクリプトがまだ実行中の状態で、 MongoDB\Collection::find()
へのcursorType
オプションで示される追尾可能 (tailable) カーソルを使用して挿入されたドキュメントを読み取るためのコンシューマー スクリプトを実行します。 最初に、 foreach
を使用してその利点を説明します。
$collection = (new MongoDB\Client)->test->capped; $cursor = $collection->find([], [ 'cursorType' => MongoDB\Operation\Find::TAILABLE_AWAIT, 'maxAwaitTimeMS' => 100, ]); foreach ($cursor as $document) { printf("Consumed document created at: %s\n", $document->createdAt); }
このコンシューマー スクリプトを実行すると、Cappedコレクション内のすべての結果をすぐに使い果たし、その後終了します。 カーソルを巻き戻すと、例外がスローされるため、2 つ目のforeach
を追加することはできません。 これは、 イテレータ を使用して反復プロセスを直接制御するための適切なユースケースです インターフェースを使用します。
$collection = (new MongoDB\Client)->test->capped; $cursor = $collection->find([], [ 'cursorType' => MongoDB\Operation\Find::TAILABLE_AWAIT, 'maxAwaitTimeMS' => 100, ]); $cursor->rewind(); while (true) { if ($cursor->valid()) { $document = $cursor->current(); printf("Consumed document created at: %s\n", $document->createdAt); } $cursor->next(); }
foreach
の例と同様に、コンシューマー スクリプト上のこのバージョンでは、Capped コレクション内のすべての結果をすばやく出力することで起動します。ただし、初期結果セットの末尾に到達しても終了しません。 追尾可能 (tailable) カーソルを使用しているため、 next()
を呼び出すと、例外がスローされるのではなく、ブロックして追加の結果を待機します。 また、 valid()
を使用して、各ステップで実際に読み取り可能なデータがあるかどうかを確認します。
TAILABLE_AWAIT
カーソルを使用するようにしたため、サーバーはドライバーへの応答を一定時間遅延させます。 この例では、MongoDB\Collection::find()
にmaxAwaitTimeMS
オプションを指定して、サーバーが約 100 ミリ秒ブロックすることをリクエストしています