Mid-Atlantic Developer Conference - Call for Speakers

The MongoDB\Driver\Cursor class

(mongodb >=1.0.0)

简介

The MongoDB\Driver\Cursor class encapsulates the results of a MongoDB command or query and may be returned by MongoDB\Driver\Manager::executeCommand() or MongoDB\Driver\Manager::executeQuery(), respectively.

类摘要

MongoDB\Driver\Cursor implements Traversable {
/* 方法 */
final private __construct ( void )
final public MongoDB\Driver\CursorId getId ( void )
final public MongoDB\Driver\Server getServer ( void )
final public bool isDead ( void )
final public void setTypeMap ( array $typemap )
final public array toArray ( void )
}

范例

Example #1 Reading a result set

MongoDB\Driver\Manager::executeCommand() and MongoDB\Driver\Manager::executeQuery() both return their results as a MongoDB\Driver\Cursor object. This object can be used to iterator over the result set that the command or cursor returned.

Because this class implements the Traversable interface, you can simply iterator over the result set by using foreach().

<?php

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

/* Insert some documents so that our query returns information */
$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 for all the items in the collection */
$query = new MongoDB\Driver\Query( [] );

/* Query the "asteroids" collection of the "test" database */
$cursor $manager->executeQuery("test.asteroids"$query);

/* $cursor now contains an object that wraps around the result set. Use
 * foreach() to iterate over all the result */
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
}

Example #2 Reading from a tailable cursors

Tailable cursors are special cursors in MongoDB that allow you to read results from a cursor, and then wait until more documents become available in the collection that match the query. This functionality only works with Capped Collections and » Change Streams, and requires a different way of iteration.

Where normal cursors can be iterated over with foreach(), the same does not work with tailable cursors as you can not call foreach() twice. In order to continuously read from a » Tailable Cursor, you will need to wrap the MongoDB\Driver\Cursor object with an IteratorIterator.

In the example below, we set up a » Capped Collection, into which we insert a few documents. We then run the query with the special cursor options tailable, awaitData and maxAwaitTimeMS. These options instruct the server to: keep the cursor open after the initial result set has been returned (tailable), and to block the read (awaitData) for at most maxAwaitTimeMS milliseconds. We then wrap the cursor in IteratorIterator and use IteratorIterator::valid() and IteratorIterator::next() to iterate over the result set.

<?php

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

/* Create capped collection "asteroids" on "test" database */
$manager->executeCommand("test", new MongoDB\Driver\Command([
    
'create' => "asteroids",
    
'capped' => true,
    
'size' => 1048576,
]));

/* Insert some documents so that our query returns information */
$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 for all the items in the collection, and make it tailable with a
 * maximum wait time of 10 seconds */
$query = new MongoDB\Driver\Query(
    [],
    [
        
'tailable' => true,
        
'awaitData' => true,
        
'maxAwaitTimeMS' => 10000,
    ]
);

/* Query the "asteroids" collection of the "test" database */
$cursor $manager->executeQuery("test.asteroids"$query);

/* Wrap cursor and rewind */
$iterator = new IteratorIterator($cursor);
$iterator->rewind();

/* Loop over the result set with valid() and next() */
while ($iterator->valid()) {
    
$document $iterator->current();
    echo 
date(DateTime::ISO8601), "\n";
    
print_r($document);

    
$iterator->next();
}

?>

During the second "Waiting", we insert another document into the collection. You can see on the date/time stamps that there are several seconds between the second and third result being returned.

以上例程的输出类似于:

2018-01-03T16:59:21+0000
stdClass Object
(
    [_id] => MongoDB\BSON\ObjectId Object
        (
            [oid] => 5a4d0be9122d3324914394e2
        )

    [name] => Ceres
    [size] => 946
    [distance] => 2.766
)

2018-01-03T16:59:21+0000
stdClass Object
(
    [_id] => MongoDB\BSON\ObjectId Object
        (
            [oid] => 5a4d0be9122d3324914394e3
        )

    [name] => Vesta
    [size] => 525
    [distance] => 2.362
)

2018-01-03T16:59:24+0000
stdClass Object
(
    [_id] => MongoDB\BSON\ObjectId Object
        (
            [oid] => 5a4d0becca67a2be8d10550c
        )

    [name] => Pallas
    [size] => 512
    [distance] => 2.773
)

错误/异常

When iterating over the cursor object, BSON data is converted into PHP variables. This iteration can cause the following Exceptions:

Table of Contents

add a note add a note

User Contributed Notes 4 notes

up
13
max-p at max-p dot me
2 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
peichi40233 at gmail dot com
10 months 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
4
tdrpic
1 year 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
2
mikemartin2016 at gmail dot com
2 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]
To Top