MongoDB\Driver\Cursor 类

(mongodb >=1.0.0)

介绍

MongoDB\Driver\Cursor 类封装了 MongoDB 命令或查询的结果,并且可能由 MongoDB\Driver\Manager::executeCommand()MongoDB\Driver\Manager::executeQuery() 返回,分别。

类概要

final class MongoDB\Driver\Cursor implements MongoDB\Driver\CursorInterface, Iterator {
/* 方法 */
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
}

变更日志

版本 描述
PECL mongodb 1.9.0 实现 Iterator.
PECL mongodb 1.6.0 实现 MongoDB\Driver\CursorInterface,它扩展了 Traversable.

示例

示例 #1 读取结果集

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( [] );

/* 查询 "test" 数据库的 "asteroids" 集合 */
$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 游标类型,允许客户端读取一些结果,然后等待更多文档变为可用。这些游标主要与 » 有上限集合» 变更流 一起使用。

虽然可以使用 foreach 迭代一次普通游标,但这种方法不适用于可尾随游标。当 foreach 与可尾随游标一起使用时,循环将在到达初始结果集的末尾时停止。尝试使用第二个 foreach 继续迭代游标将抛出异常,因为 PHP 尝试重绕游标。类似于其他数据库驱动程序中的结果对象,MongoDB 中的游标只支持向前迭代,这意味着它们不能被重绕。

为了持续从可尾随游标读取,必须使用 IteratorIterator 包装 Cursor 对象。这允许应用程序直接控制游标的迭代,避免无意中重绕游标,并决定何时等待新结果或完全停止迭代。

为了演示可尾随游标的实际操作,将使用两个脚本:一个“生产者”和一个“消费者”。生产者脚本将使用 » 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);
}

?>

在生产者脚本仍在运行的情况下,可以执行第二个消费者脚本,使用尾部游标读取插入的文档,尾部游标由 tailableawaitData 选项指示,用于 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("Consumed document created at: %s\n", $document->createdAt);
}

$iterator->next();
}

?>

消费者脚本将首先快速打印限定集合中所有可用的文档(就好像使用了 foreach 一样);但是,它不会在到达初始结果集的末尾时终止。由于游标是尾部游标,因此调用 IteratorIterator::next() 会阻塞并等待其他结果。 IteratorIterator::valid() 也用于检查在每个步骤中是否实际有数据可供读取。

注意: 此示例使用 awaitData 查询选项来指示服务器在结果集结束时阻塞一小段时间(例如一秒钟),然后再向驱动程序返回响应。这用于防止驱动程序在没有结果可用时积极地轮询服务器。 maxAwaitTimeMS 选项可以与 tailableawaitData 结合使用,以指定服务器在到达结果集末尾时应阻塞的时间。

错误/异常

在迭代游标对象时,BSON 数据被转换为 PHP 变量。此迭代会导致以下异常

目录

添加注释

用户贡献的注释 5 个注释

max-p at max-p dot me
8 年前
正如人们可能注意到的,与现在已弃用的 Mongo 驱动程序相反,此类没有实现 hasNext() 或 next() 方法。

如果出于任何原因,您需要以过程方式从游标中提取数据,或者需要在迭代游标时覆盖 foreach 的行为,可以使用 SPL \IteratorIterator 类。这样做时,在使用迭代器之前对其进行回绕非常重要,否则您将不会获得任何数据。

<?php
$cursor
= $collection->find();
$it = new \IteratorIterator($cursor);
$it->rewind(); // 非常重要

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

我使用了这个技巧来构建一个向后兼容的包装器,模拟旧的 Mongo 驱动程序,以升级旧的代码库。
tdrpic
8 年前
如果您发现使用数组(而不是对象)来表示返回的文档更容易,请在执行查询后添加以下内容

$cursor->setTypeMap(['root' => 'array', 'document' => 'array', 'array' => 'array']);
mikemartin2016 at gmail dot com
8 年前
我注意到游标中缺少 ->sort。似乎旧的驱动程序具有更多功能。

[红色:驱动程序之间的游标创建方式不同。在旧的驱动程序中,游标要到迭代器的第一个 rewind() 调用之后才会创建。

在新的驱动程序中,游标已经存在。由于 sort(以及 limit 和 skip)参数需要发送到服务器,因此在游标已经创建后无法调用它们。

您也可以在新的驱动程序中使用 sort(以及 limit 和 skip),方法是将它们作为选项指定给 Query,如以下示例所示:https://php.net/manual/en/mongodb-driver-query.construct.php#refsect1-mongodb-driver-query.construct-examples]
peichi40233 at gmail dot com
7 年前
旧的 mongo 扩展中曾经有一个 count() 方法 (http://docs.php.net/manual/en/mongocursor.count.php),但是,这个功能似乎在 mongodb 中被删除了。

我看到一些人使用 executeCommand() 来做到这一点,但我发现使用 toArray() 方法并计算返回的数组更容易。

例如
$manager = new MongoDB\Driver\Manager();
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $manager->executeQuery('db.collection', $query)->toArray();
var_dump(count($cursor));
cg at papoo dot de
2 年前
从 php-mongodb 1.9.0 版本开始,Cursor 实现了 Iterator,但如果您还需要支持旧版本,则可以有条件地用 IteratorIterator 包装游标

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

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