Пример #1 Reading a result set
Поскольку MongoDB\Driver\Cursor реализует интерфейс
Traversable, вы можете
итерировать по набору результата с помощью
foreach
.
<?php
$manager = new MongoDB\Driver\Manager();
/* Вставить определённые документы, чтобы наш запрос вернул результаты */
$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);
/* Запрос на получение всех элементов в коллекции */
$query = new MongoDB\Driver\Query( [] );
/* Запрос коллекции "asteroids" базы данных "test" */
$cursor = $manager->executeQuery("test.asteroids", $query);
/* Теперь $cursor содержит объект, обёрнутый вокруг набора с результатом. Используйте
* foreach() для итеации по всему результату */
foreach ($cursor as $document) {
print_r($document);
}
?>
Вывод приведённого примера будет похож на:
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
}
Пример #2 Чтение набора результатов для хвостового курсора
» Хвостовые курсоры -
- это особый тип курсора MongoDB, который позволяет клиенту читать некоторые результаты,
а затем ждать, пока не появятся дополнительные документы.
Эти курсоры в основном используются с
» Capped Collections
и » Change Streams.
Хотя обычные курсоры можно итерировать один раз с помощью foreach
,
этот подход не будет работать с хвостовыми курсорами.
Когда foreach
используется с хвостовым курсором,
цикл останавливается по достижении конца начального набора результатов.
Попытка продолжить итерацию курсора со вторым foreach
выбросить исключение,
поскольку PHP пытается перемотать курсор. Подобно объектам результатов в других драйверах баз данных,
курсоры в MongoDB поддерживают только итерацию вперёд, что означает, что они не могут быть перемотаны.
Для непрерывного считывания с хвостового курсора объект курсора должен быть завернут
с помощью IteratorIterator. Это позволяет приложению напрямую управлять
итерацией курсора, избегать непреднамеренного перемотки курсора и решать, когда ждать новых результатов
или полностью прекратить итерацию.
Чтобы продемонстрировать хвостовой курсор в действии,
будут использоваться два скрипта: "производитель" (producer) и "потребитель" (consumer).
Скрипт продюсера создаст новую capped-коллекцию, используя команду
» create
и начнёт вставку нового документа в эту коллекцию каждую секунду.
<?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);
}
?>
Когда скрипт продюсера (producer) всё ещё запущен,
может быть выполнен второй пользовательский скрипт для чтения вставленных документов
с помощью хвостового (tailable) курсора, обозначенного параметрами
tailable
и awaitData
для 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("Пользовательский документ создан: %s\n", $document->createdAt);
}
$iterator->next();
}
?>
Пользовательский скрипт начнёт с быстрой печати всех доступных документов
в заблокированной коллекции (как если бы использовался foreach
);
однако при достижении конца начального набора результатов он не завершится.
Так как курсор является хвостовым, вызов IteratorIterator::valid()
будет блокировать и ждать дополнительных результатов.
IteratorIterator::valid() также используется для проверки наличия на
каждом этапе данных, доступных для чтения.
Замечание:
В этом примере используется опция запроса awaitData
,
чтобы проинструктировать сервер блокировать в течение короткого периода
(например, одну секунду) в конце набора результатов перед возвратом ответа драйверу.
Это используется для предотвращения агрессивного опроса (polling) сервера
при отсутствии результатов. Параметр maxAwaitTimeMS
может
использоваться в сочетании с tailable
и awaitData
,
чтобы указать время, которое сервер должен блокировать, когда он достигнет конца набора результатов.