Overview
En esta guía, puedes aprender cómo acceder a datos desde un cursor usando la librería PHP de MongoDB.
Un cursor es un mecanismo que devuelve los resultados de una operación de lectura en lotes iterables. Los cursores reducen tanto el consumo de memoria como el número de solicitudes al servidor al mantener solo un subconjunto de documentos en cualquier momento, en lugar de devolver todos los documentos a la vez.
Cada vez que la librería de PHP de MongoDB realiza una operación de lectura usando el MongoDB\Collection::find()
método, devuelve los documentos coincidentes en una instancia MongoDB\Driver\Cursor. La clase Cursor implementa la de PHP IteradorInterfaz que proporciona mayor control sobre la iteración y mayor compatibilidad con funciones PHP que trabajan con iterables. Los cursores de MongoDB solo admiten la iteración hacia adelante, por lo que no se puede rebobinar un cursor ni usar un foreach bucle varias veces.
Datos de muestra
Los ejemplos de esta guía utilizan la colección restaurants en la base de datos sample_restaurants de los conjuntos de datos de muestra de Atlas. Para acceder a esta colección desde tu aplicación PHP, instancia un MongoDB\Client que se conecte a un clúster Atlas y asigna el siguiente valor a tu variable $collection:
$collection = $client->sample_restaurants->restaurants;
Para saber cómo crear una implementación gratuita de MongoDB y cargar los conjuntos de datos de ejemplo, consulta la guía MongoDB Primeros Pasos.
Acceder al contenido del cursor de forma iterativa
La clase MongoDB\Driver\Cursor implementa la interfaz Iterator, por lo que puedes utilizar un bucle foreach para iterar a través de su contenido.
El siguiente ejemplo utiliza el método MongoDB\Collection::find() para recuperar todos los documentos cuyo valor del campo name es 'Dunkin' Donuts'. A continuación, imprime cada documento desde el cursor devuelto por el método find():
$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); foreach ($cursor as $doc) { echo json_encode($doc), PHP_EOL; }
{"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40379573"} {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40363098"} {"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40395071"} ...
Recuperar documentos individualmente
Para recuperar un documento individual de un cursor, llama al método current() en una instancia MongoDB\Driver\Cursor. Este método devuelve el documento al que el cursor apunta inicialmente. Puedes seguir avanzando el cursor llamando al método next(), lo que instruye al cursor para que apunte al siguiente documento recuperado.
El siguiente ejemplo busca todos los documentos cuyo valor del campo name sea 'Dunkin' Donuts'. A continuación, imprime el primer documento recuperado llamando al método current() en un cursor:
$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); $cursor->rewind(); echo json_encode($cursor->current());
{"_id":{"$oid":"..."},..."name":"Dunkin' Donuts","restaurant_id":"40379573"}
Recuperar todos los documentos
Advertencia
Si la cantidad y el tamaño de los documentos devueltos por su consulta exceden la memoria disponible de la aplicación, el programa se bloqueará. Si espera un conjunto de resultados grande, acceda al cursor iterativamente.
Para recuperar todos los documentos desde un cursor, convierte el cursor en un arreglo utilizando cualquiera de los siguientes métodos:
MongoDB\\Driver\\Cursor::toArray(): Llamada a un objetoMongoDB\Driver\Cursoriterator_to_array(): Pasa un objetoMongoDB\Driver\Cursorcomo parámetro
El siguiente ejemplo llama al método toArray() en un cursor para almacenar sus resultados en un arreglo:
$cursor = $collection->find(['name' => 'Dunkin\' Donuts']); $resultArray = $cursor->toArray();
Cursores con seguimiento
Si deseas que un cursor permanezca abierto después de que tu cliente lea su contenido inicial, puedes utilizar un cursor con seguimiento. Se recomienda usar cursores con seguimiento para consultar colecciones con tamaño fijo.
No puedes usar un bucle foreach para iterar un cursor con seguimiento, ya que el bucle termina después de leer el conjunto de resultados inicial del cursor. Si utilizas un segundo bucle foreach para seguir iterando el cursor con seguimiento, la librería de PHP intentará rebobinar el cursor y luego generará un error. En vez de eso, se deben usar los métodos de la interfaz Iterador para recuperar resultados de un cursor con seguimiento.
Para crear un cursor con seguimiento, define la opción cursorType en MongoDB\Operation\Find::TAILABLE en un arreglo. A continuación, pasa el arreglo como parámetro de opciones al método MongoDB\Collection::find().
ejemplo de cursor con seguimiento
Esta sección proporciona los siguientes scripts de ejemplo, que puedes ejecutar simultáneamente:
Un script de productor que crea una colección con tamaño fijo e inserta documentos en ella
Un script de consumidor que crea un cursor adaptable para leer documentos de la colección limitada
Crea y llena una colección
El siguiente ejemplo crea una colección con tamaño fijo llamada vegetables y espera 5 segundos antes de insertar un documento adicional en la colección:
$db = $client->db; $db->createCollection( 'vegetables', ['capped' => true, 'size' => 1024 * 1024], ); $vegetables = [ ['name' => 'cauliflower', 'createdAt' => new MongoDB\BSON\UTCDateTime()], ['name' => 'zucchini', 'createdAt' => new MongoDB\BSON\UTCDateTime()], ]; $collection = $db->vegetables; $result = $collection->insertMany($vegetables); sleep(5); $collection->insertOne(['name' => 'carrot', 'createdAt' => new MongoDB\BSON\UTCDateTime()]);
Crear un cursor adaptable
Mientras el anterior ejemplo de código se está ejecutando, use el siguiente código para crear un cursor con seguimiento y recuperar todos los documentos en la colección vegetables:
$cursor = $collection->find([], ['cursorType' => MongoDB\Operation\Find::TAILABLE]); $cursor->rewind(); $docsFound = 0; while ($docsFound < 3) { if ($cursor->valid()) { $doc = $cursor->current(); echo json_encode($doc), PHP_EOL; $docsFound++; } $cursor->next(); }
{"_id":{"$oid":"..."},"name":"cauliflower","createdAt":{"$date":{"$numberLong":"..."}}} {"_id":{"$oid":"..."},"name":"zucchini","createdAt":{"$date":{"$numberLong":"..."}}} {"_id":{"$oid":"..."},"name":"carrot","createdAt":{"$date":{"$numberLong":"..."}}}
Este código imprime los dos documentos iniciales en la colección, pero el bucle while no se termina hasta recibir un tercer documento. El método next() se asegura de que el código espere los resultados adicionales del cursor.
Tip
Para obtener más información sobre los cursores con seguimiento, consulta cursores con seguimiento en el manual del servidor de MongoDB.
Información Adicional
Para obtener más información sobre las operaciones de lectura, consulte el Retrieve Data guide.
Para obtener más información sobre cursores, véase las siguientes páginas en la documentación de la API de extensión:
Documentación de la API
Para obtener más información sobre el método find(), consulta la documentación de la API para MongoDB\Collection::find().