Los » cursores rastreables
son un tipo especial de cursor de MongoDB que permite al cliente leer algunos
resultados y luego esperar hasta que haya más documentos disponibles. Estos
cursores se usan principalmente con
» colecciones limitadas
y » flujos de cambios.
Mientras que los cursores normales pueden iterarse una vez con
foreach, ese enfoque no funcionará con cursores rastreables.
Cuando se usa foreach con un cursor rastreable, el bucle
terminará al llegar al final del conjunto de resultados inicial. Intentar
continuar la iteración en el cursor con un segundo
foreach lanzaría una excepción, ya que PHP intenta
retroceder el cursor. Al igual que los objetos de resultado en otros controladores
de bases de datos, los cursores en MongoDB solo admiten la iteración hacia
adelante, lo que significa que no pueden retrocederse.
Para leer de forma continua desde un cursor rastreable, el objeto Cursor
debe envolverse con un IteratorIterator. Esto permite
que la aplicación controle directamente la iteración del cursor, evite
retroceder el cursor sin querer y decida cuándo esperar nuevos resultados
o detener completamente la iteración.
Para demostrar un cursor rastreable en acción, se usarán dos scripts: un
"productor" y un "consumidor". El script productor creará una nueva colección
limitada usando el comando
» create e insertará
un nuevo documento en esa colección cada segundo.
<?php
$manager = new MongoDB\Driver\Manager;
$manager->executeCommand('test', new MongoDB\Driver\Command([
'create' => 'asteroids',
'capped' => true,
'size' => 1048576,
]));
while (true) {
$bulkWrite = new MongoDB\Driver\BulkWrite;
$bulkWrite->insert(['createdAt' => new MongoDB\BSON\UTCDateTime]);
$manager->executeBulkWrite('test.asteroids', $bulkWrite);
sleep(1);
}
?>
Con el script productor aún en ejecución, puede ejecutarse un segundo script
consumidor para leer los documentos insertados usando un cursor rastreable,
indicado por las opciones tailable y
awaitData en MongoDB\Driver\Query::__construct().
<?php
$manager = new MongoDB\Driver\Manager;
$query = new MongoDB\Driver\Query([], [
'tailable' => true,
'awaitData' => true,
]);
$cursor = $manager->executeQuery('test.asteroids', $query);
$iterator = new IteratorIterator($cursor);
$iterator->rewind();
while (true) {
if ($iterator->valid()) {
$document = $iterator->current();
printf("Documento consumido creado en: %s\n", $document->createdAt);
}
$iterator->next();
}
?>
El script consumidor comenzará imprimiendo rápidamente todos los documentos
disponibles en la colección limitada (como si se hubiera usado
foreach); sin embargo, no terminará al llegar al final
del conjunto de resultados inicial. Dado que el cursor es rastreable, llamar
a IteratorIterator::next() bloqueará y esperará
resultados adicionales. IteratorIterator::valid() también
se usa para verificar si hay realmente datos disponibles para leer en cada
paso.