Longhorn PHP 2026 - Call For Papers

La clase MongoDB\Driver\Cursor

(mongodb >=1.0.0)

Introducción

La clase MongoDB\Driver\Cursor encapsula los resultados de un comando o consulta de MongoDB y puede ser devuelta por MongoDB\Driver\Manager::executeCommand() o MongoDB\Driver\Manager::executeQuery(), respectivamente.

Sinopsis de la Clase

final class MongoDB\Driver\Cursor implements MongoDB\Driver\CursorInterface {
/* Métodos */
final private __construct()
final public getId(): MongoDB\BSON\Int64
final public isDead(): bool
public key(): int
public next(): void
public rewind(): void
final public setTypeMap(array $typemap): void
final public toArray(): array
public valid(): bool
}

Historial de cambios

Versión Descripción
PECL mongodb 1.9.0 Implementa Iterator.
PECL mongodb 1.6.0 Implementa MongoDB\Driver\CursorInterface, que extiende Traversable.

Ejemplos

Ejemplo #1 Lectura de un conjunto de resultados

MongoDB\Driver\Manager::executeCommand() y MongoDB\Driver\Manager::executeQuery() devuelven sus resultados como un objeto MongoDB\Driver\Cursor. Este objeto puede usarse para iterar sobre el conjunto de resultados del comando o consulta.

Dado que MongoDB\Driver\Cursor implementa la interfaz Traversable, puede simplemente iterar sobre el conjunto de resultados con foreach.

<?php

$manager
= new MongoDB\Driver\Manager();

/* Insertar algunos documentos para que nuestra consulta devuelva información */
$bulkWrite = new MongoDB\Driver\BulkWrite;
$bulkWrite->insert(['name' => 'Ceres', 'size' => 946, 'distance' => 2.766]);
$bulkWrite->insert(['name' => 'Vesta', 'size' => 525, 'distance' => 2.362]);
$manager->executeBulkWrite("test.asteroids", $bulkWrite);

/* Consultar todos los elementos de la colección */
$query = new MongoDB\Driver\Query( [] );

/* Consultar la colección "asteroids" de la base de datos "test" */
$cursor = $manager->executeQuery("test.asteroids", $query);

/* $cursor ahora contiene un objeto que envuelve el conjunto de resultados. Usar
* foreach() para iterar sobre todos los resultados */
foreach($cursor as $document) {
print_r($document);
}

?>

Resultado del ejemplo anterior es similar a:

stdClass Object
(
    [_id] => MongoDB\BSON\ObjectId Object
        (
            [oid] => 5a4cff2f122d3321565d8cc2
        )

    [name] => Ceres
    [size] => 946
    [distance] => 2.766
)
stdClass Object
(
    [_id] => MongoDB\BSON\ObjectId Object
        (
            [oid] => 5a4cff2f122d3321565d8cc3
        )

    [name] => Vesta
    [size] => 525
    [distance] => 2.362
}

Ejemplo #2 Lectura de un conjunto de resultados para un cursor rastreable

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.

Nota: Este ejemplo usa la opción de consulta awaitData para instruir al servidor que bloquee durante un breve período (por ejemplo, un segundo) al final del conjunto de resultados antes de devolver una respuesta al controlador. Esto se usa para evitar que el controlador consulte agresivamente al servidor cuando no hay resultados disponibles. La opción maxAwaitTimeMS puede usarse junto con tailable y awaitData para especificar la cantidad de tiempo que el servidor debe bloquearse cuando llega al final del conjunto de resultados.

Errores/Excepciones

Al iterar sobre el objeto cursor, los datos BSON se convierten en variables PHP. Esta iteración puede causar las siguientes Excepciones:

Tabla de contenidos

add a note

User Contributed Notes 5 notes

up
16
max-p at max-p dot me
10 years ago
As one might notice, this class does not implement a hasNext() or next() method as opposed to the now deprecated Mongo driver.

If, for any reason, you need to pull data from the cursor procedurally or otherwise need to override the behavior of foreach while iterating on the cursor, the SPL \IteratorIterator class can be used. When doing so, it is important to rewind the iterator before using it, otherwise you won't get any data back.

<?php
$cursor = $collection->find();
$it = new \IteratorIterator($cursor);
$it->rewind(); // Very important

while($doc = $it->current()) {
    var_dump($doc);
    $it->next();
}
?>

I used this trick to build a backward compatibility wrapper emulating the old Mongo driver in order to upgrade an older codebase.
up
5
tdrpic
9 years ago
If you find that it would be easier to use arrays (instead of objects) for the returned documents, add the following after executing your query:

$cursor->setTypeMap(['root' => 'array', 'document' => 'array', 'array' => 'array']);
up
4
mikemartin2016 at gmail dot com
10 years ago
I noticed that  ->sort is missing from the cursor.  Seems like the old driver has more functionality.

[red.: The way how cursors are created is different between the drivers. In the old driver, the cursor would not be created until after the first rewind() call on the iterator.

In the new driver the cursor already exists. Because sort (and limit and skip) parameters need to be send to the server, they can not be called after the cursor already has been created.

You can use sort (and limit and skip) with the new driver as well, by specifying them as options to the Query as shown in this example: http://php.net/manual/en/mongodb-driver-query.construct.php#refsect1-mongodb-driver-query.construct-examples]
up
4
peichi40233 at gmail dot com
9 years ago
There used to be a count() method in the old mongo extension (http://docs.php.net/manual/en/mongocursor.count.php), however, this feature seems to be deleted in mongodb.

I've seen some people use executeCommand() to do that, but I found it much more earier to just use the toArray() method and count the returned array.

For example:
$manager = new MongoDB\Driver\Manager();
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $manager->executeQuery('db.collection', $query)->toArray();
var_dump(count($cursor));
up
1
cg at papoo dot de
4 years ago
Since php-mongodb version 1.9.0 Cursor implements Iterator, but if you need to support older versions too, you can conditionally wrap the cursor with IteratorIterator:

<?php
$iterator = $collection->find();

if (!($iterator implements Iterator)) {
  $iterator = new \IteratorIterator($iterator);
}
?>
To Top