(mongodb >=1.0.0)
Класс MongoDB\Driver\Cursor содержит результаты команды MongoDB command или запроса и может быть возвращён MongoDB\Driver\Manager::executeCommand() или MongoDB\Driver\Manager::executeQuery() соответственно.
Версия | Описание |
---|---|
PECL-модуль mongodb 1.9.0 | Класс теперь реализует интерфейс Iterator. |
PECL-модуль mongodb 1.6.0 | Класс теперь реализует интерфейс MongoDB\Driver\CursorInterface, который наследует Traversable. |
Пример #1 Reading a result set
Методы MongoDB\Driver\Manager::executeCommand() и MongoDB\Driver\Manager::executeQuery() возвращают результаты в виде объекта MongoDB\Driver\Cursor.
Поскольку класс 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
, чтобы указать время, которое сервер должен блокировать, когда он достигнет конца набора результатов.
При итерации по объекту курсора BSON-данные преобразовываются в PHP-переменные. Эта итерация иногда вызывает следующие исключения: