PHP 8.4.1 Released!

A classe MongoDB\Driver\Cursor

(mongodb >=1.0.0)

Introdução

A classe MongoDB\Driver\Cursor encapsula os resultados de um comando ou consulta MongoDB e podem ser retornados por MongoDB\Driver\Manager::executeCommand() ou MongoDB\Driver\Manager::executeQuery(), respectivamente.

Resumo da classe

final class MongoDB\Driver\Cursor implements MongoDB\Driver\CursorInterface, Iterator {
/* Métodos */
final private __construct()
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
}

Registro de Alterações

Versão Descrição
PECL mongodb 1.9.0 Implementa Iterator.
PECL mongodb 1.6.0 Implementa MongoDB\Driver\CursorInterface, que estende Traversable.

Exemplos

Exemplo #1 Lendo um conjunto de resultados

MongoDB\Driver\Manager::executeCommand() e MongoDB\Driver\Manager::executeQuery() ambos retornam seus resultados como um objeto MongoDB\Driver\Cursor. Este objeto pode ser usado para iterar sobre conjunto de resultados do comando ou consulta.

Como MongoDB\Driver\Cursor implementa a interface Traversable, pode-se simplesmente iterar pelo conjunto de resultados com foreach.

<?php

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

/* Insere alguns documentos para que a consulta retorne informação */
$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);

/* Consulta todos os itens na coleção */
$query = new MongoDB\Driver\Query( [] );

/* Consulta a coleção "asteroids" do banco de dados "test" */
$cursor = $manager->executeQuery("test.asteroids", $query);

/* $cursor agora contém um objeto que envolve o conjunto de resultados. Pode-se
* usar foreach() para iterar por todo o resultado */
foreach($cursor as $document) {
print_r($document);
}

?>

O exemplo acima produzirá algo semelhante 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
}

Exemplo #2 Reading a result set for a tailable cursor

» Cursores adaptáveis são um tipo especial de cursor no MongoDB que permite ao cliente ler alguns resultado e então esperar até que mais documentos fiquem disponíveis. Esses cursores são usado principalmente com » Coleções Limitadas e » Fluxos de Alterações.

Enquanto os cursores normais podem ser iterados com foreach, esse método não irá funcionar com cursores adaptáveis. Quando foreach é usado com um cursor adaptável, a repetição irá terminar quando alcançar o final do conjunto de resultados inicial. A tentativa de continuar a iteração no cursor com um segundo foreach lançaria uma exceção, já que o PHP tentaria retroceder o cursor. De forma similar aos objetos de resultados em outros drivers de bancos de dados, os cursores no MongoDB suportam apenas iteração para a frente, ou seja, eles não podem ser retrocedidos.

Para ler continuamente a partir de um cursor adaptável, o objeto Cursor deve ser encapsulado com um IteratorIterator. Isso permite que a aplicação controle diretamente a iteração do cursor, evite retroceder inadvertidamente o cursor e decida quando esperar por novos resultados ou interromper totalmente a iteração.

Para demonstrar um cursor adaptável em ação, serão utilizados dois scripts: um "produtor" e um "consumidor". O script produtor criará uma nova coleção limitada usando o comando » create e procederá à inserção de um novo documento nessa coleção a 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);
}

?>

Com o script produtor ainda em execução, um segundo script consumidor pode ser executado para ler os documentos inseridos usando um cursor adaptável, indicado pelas opções tailable e awaitData para o método 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 criado em: %s\n", $document->createdAt);
}

$iterator->next();
}

?>

O script consumidor começará mostrando rapidamente todos os documentos disponíveis na coleção limitada (como se foreach tivesse sido usado); entretanto, ele não terminará ao atingir o final do conjunto de resultados inicial. Como o cursor pode ser seguido, chamar IteratorIterator::next() bloqueará e aguardará resultados adicionais. IteratorIterator::valid() também é usado para verificar se realmente há dados disponíveis para leitura em cada etapa.

Nota: Este exemplo usa a opção de consulta awaitData para instruir o servidor a bloquear por um curto período (por exemplo, um segundo) no final do conjunto de resultados antes de retornar uma resposta ao driver. Isso é usado para evitar que o driver faça uma sondagem agressiva no servidor quando não houver resultados disponíveis. A opção maxAwaitTimeMS pode ser usada em conjunto com tailable e awaitData para especificar a quantidade de tempo que o servidor deve bloquear quando atingir o final do o conjunto de resultados.

Erros/Exceções

Ao iterar sobre o objeto cursor, os dados BSON são convertidos em variáveis ​ ​PHP. Esta iteração pode causar as seguintes exceções:

Índice

adicione uma nota

Notas Enviadas por Usuários (em inglês) 5 notes

up
16
max-p at max-p dot me
8 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
8 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
8 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
7 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
3 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