diff --git a/source/applications/read.txt b/source/applications/read.txt index 584a3694ab8..7e058b60f36 100644 --- a/source/applications/read.txt +++ b/source/applications/read.txt @@ -327,27 +327,90 @@ Consider the following examples that illustrate the use of the Cursor ~~~~~~ -:method:`find() ` returns a :term:`cursor`; -however, in the :program:`mongo` shell, the cursor is automatically -iterated up to 20 times to print the documents referenced by the -cursor. To access the documents, you must explicitly handle the -cursor, as in the following example: +The :method:`find() ` method returns a +:term:`cursor` to the results; however, in the :program:`mongo` shell, +if the returned cursor is not assigned to a variable, then the cursor +is automatically iterated up to 20 times [#setShellBatchSize]_ to print +up to the first 20 documents that match the query, as in the following +example: .. code-block:: javascript - var myCursor = db.bios.find( { _id: 1 } ); + db.bios.find( { _id: 1 } ); - var myDocument = myCursor.hasNext() ? myCursor.next() : null; +When you assign the :method:`find() ` to a +variable: - if (myDocument) { - var myName = myDocument.name; +- you can type the name of the cursor variable to iterate up to 20 + times [#setShellBatchSize]_ and print the matching documents, as in + the following example: - print (tojson(myName)); - } + .. code-block:: javascript + + var myCursor = db.bios.find( { _id: 1 } ); + + myCursor + +- you can use the cursor method :method:`next() ` to + access the documents, as in the following example: + + .. code-block:: javascript + + var myCursor = db.bios.find( { _id: 1 } ); -See the :method:`cursor.forEach()`, :method:`cursor.hasNext()`, -:method:`cursor.next()` documentation for more information on cursor -handling. + var myDocument = myCursor.hasNext() ? myCursor.next() : null; + + if (myDocument) { + + var myName = myDocument.name; + + print (tojson(myName)); + } + + To print, you can also use the ``printjson()`` method instead of + ``print(tojson())``: + + .. code-block:: javascript + + if (myDocument) { + + var myName = myDocument.name; + + printjson(myName); + } + +- you can use the cursor method :method:`forEach() ` + to iterate the cursor and access the documents, as in the following + example: + + .. code-block:: javascript + + var myCursor = db.bios.find( { _id: 1 } ); + + myCursor.forEach(printjson); + +For more information on cursor handling, see: + +- :method:`cursor.hasNext()` + +- :method:`cursor.next()` + +- :method:`cursor.forEach()` + +- :ref:`cursors ` + +- :ref:`JavaScript cursor methods` + +.. [#setShellBatchSize] You can use the ``DBQuery.shellBatchSize`` to + change the number of iteration from the default value ``20``, as in the + following example which sets the number to ``10`` : + + .. code-block:: javascript + + DBQuery.shellBatchSize = 10 + +Modify Cursor Behavior +`````````````````````` In addition to the ```` and the ```` arguments, the :program:`mongo` shell and the :doc:`drivers ` @@ -393,14 +456,36 @@ its behavior, such as: db.bios.find().skip( 5 ) -You may chain these cursor methods; however, the :method:`limit() -` method is always applied after the :method:`sort() -` even if you chain the methods in the reverse order: +You can chain these cursor methods, as in the following examples [#dbquery-server]_: .. code-block:: javascript + db.bios.find().sort( { name: 1 } ).limit( 5 ) db.bios.find().limit( 5 ).sort( { name: 1 } ) +See :ref:`JavaScript cursor methods ` and your +:doc:`driver ` documentation for more +information on cursor methods. See :ref:`read-operations-cursors` for +more information regarding cursors. + +.. [#dbquery-server] Regardless of the order you chain the :method:`limit() + ` and the :method:`sort() `, the + request to the server has the following structure that treats the + query and the :method:`sort() ` modifier as a single + object: + + .. code-block:: javascript + + db.bios.find( { $query: {}, $orderby: { name: 1 } } ).limit( 5 ) + + This structure means that the :method:`limit() ` + method is always applied after the :method:`sort() ` + regardless of the order in which the client chains the two methods. + + For other cursor modifiers that are sent with the + query as a single object to the server, see the :doc:`meta query operators + `. + .. _crud-read-findOne: .. _crud-read-find-one: diff --git a/source/core/document.txt b/source/core/document.txt index fd7602158af..8f639ef672a 100644 --- a/source/core/document.txt +++ b/source/core/document.txt @@ -211,12 +211,9 @@ Consider the following options for the value of an ``_id`` field: additional index. - Generate a sequence number for the documents in your collection in - your application and use this value for the ``_id`` value. - - .. TODO add the following when the tutorial is live - - see the :doc:`/tutorial/create-an-auto-incrementing-field` - tutorial for an implementation pattern. + your application and use this value for the ``_id`` value. See the + :doc:`/tutorial/create-an-auto-incrementing-field` tutorial for an + implementation pattern. - Generate a UUID in your application code. For efficiency, store the UUID as a value of the BSON ``BinData`` type to reduce the diff --git a/source/core/read-operations.txt b/source/core/read-operations.txt index bdb1af47256..3e5e31ffd85 100644 --- a/source/core/read-operations.txt +++ b/source/core/read-operations.txt @@ -543,7 +543,7 @@ the query used an index. This query: - returned 5 documents, as indicated by the :data:`n` field; - scanned 5 documents from the index, as indicated by the - :data:`nscanned`` field; + :data:`nscanned` field; - then read 5 full documents from the collection, as indicated by the :data:`nscannedObjects` field. @@ -656,6 +656,208 @@ indexes at all. Consider the following situations: cannot use an index. *However*, the regular expression with anchors to the beginning of a string *can* use an index. +.. _read-operations-cursors: + +Cursors +------- + +The :method:`find() ` method returns a +:term:`cursor` to the results; however, in the :program:`mongo` shell, +if the returned cursor is not assigned to a variable, then the cursor +is automatically iterated up to 20 times [#setShellBatchSize]_ to print +up to the first 20 documents that match the query, as in the following +example: + +.. code-block:: javascript + + db.inventory.find( { type: 'food' } ); + +When you assign the :method:`find() ` to a +variable: + +- you can type the name of the cursor variable to iterate up to 20 + times [#setShellBatchSize]_ and print the matching documents, as in + the following example: + + .. code-block:: javascript + + var myCursor = db.inventory.find( { type: 'food' } ); + + myCursor + +- you can use the cursor method :method:`next() ` to + access the documents, as in the following example: + + .. code-block:: javascript + + var myCursor = db.inventory.find( { type: 'food' } ); + + var myDocument = myCursor.hasNext() ? myCursor.next() : null; + + if (myDocument) { + + var myItem = myDocument.item; + + print(tojson(myItem)); + } + + To print, you can also use the ``printjson()`` method instead of + ``print(tojson())``: + + .. code-block:: javascript + + if (myDocument) { + + var myItem = myDocument.item; + + printjson(myItem); + } + +- you can use the cursor method :method:`forEach() ` + to iterate the cursor and access the documents, as in the following + example: + + .. code-block:: javascript + + var myCursor = db.inventory.find( { type: 'food' } ); + + myCursor.forEach(printjson); + +See :ref:`JavaScript cursor methods ` and your +:doc:`driver ` documentation for more +information on cursor methods. + +.. [#setShellBatchSize] You can use the ``DBQuery.shellBatchSize`` to + change the number of iteration from the default value ``20``, as in the + following example which sets the number to ``10``: + + .. code-block:: javascript + + DBQuery.shellBatchSize = 10 + +Iterator Index +~~~~~~~~~~~~~~ + +In the :program:`mongo` shell, you can use the ``toArray()`` method to +iterate the cursor and return the documents in an array, as in the +following: + +.. code-block:: javascript + + var myCursor = db.inventory.find( { type: 'food' } ); + var documentArray = myCursor.toArray(); + var myDocument = documentArray[3]; + +The ``toArray()`` method loads into RAM all documents returned by the +cursor; the ``toArray()`` method exhausts the cursor. + +Additionally, some :doc:`drivers ` provide +access to the documents by using an index on the cursor (i.e. +``cursor[index]``). This is a shortcut for first calling the +``toArray()`` method and then using an index on the resulting array. + +Consider the following example: + +.. code-block:: javascript + + var myCursor = db.inventory.find( { type: 'food' } ); + var myDocument = myCursor[3]; + +The ``myCursor[3]`` is equivalent to the following example: + +.. code-block:: javascript + + myCursor.toArray() [3]; + +.. TODO link to toArray() method once the page has been added + +Cursor Considerations +~~~~~~~~~~~~~~~~~~~~~ + +Consider the following behaviors related to cursors: + +- By default, the server will automatically close the cursor after 10 + minutes of inactivity or if the cursor has been exhausted. To + override this behavior, you can specify the ``noTimeout`` :wiki:`wire + protocol flag ` in your query; however, you + should either close the cursor manually or exhaust the cursor. In the + :program:`mongo` shell, you can set the ``noTimeout`` flag + [#queryOptions]_: + + .. code-block:: javascript + + var myCursor = db.inventory.find().addOption(DBQuery.Option.noTimeout); + + See your :doc:`driver ` documentation for + information on setting the ``noTimeout`` flag. + +- Because the cursor is not isolated during its lifetime, intervening + write operations may cause a document to be returned multiple times. + To handle this situation, see the information on :wiki:`snapshot mode + `. + +- The MongoDB server returns the query results in batches: + + - For most queries, the *first* batch returns 101 documents or just + enough documents to exceed 1 megabyte. Subsequent batch size is 4 + megabytes. To override the default size of the batch, see + :method:`cursor.batchSize()` and :method:`cursor.limit()`. + + - For queries that include a sort operation *without* an index, the + server must load all the documents in memory to perform the sort + and will return all documents in the first batch. + + - Batch size will not exceed the :ref:`maximum BSON document size + `. + + - As you iterate through the cursor and reach the end of the returned + batch, if there are more results, :method:`cursor.next()` will + perform a :data:`getmore operation ` to retrieve the next batch. + + To see how many documents remain in the batch as you iterate the + cursor, you can use the :method:`cursor.objsLeftInBatch()` method, + as in the following example: + + .. code-block:: javascript + + var myCursor = db.inventory.find(); + + var myFirstDocument = myCursor.hasNext() ? myCursor.next() : null; + + myCursor.objsLeftInBatch(); + +- You can use the command :dbcommand:`cursorInfo` to retrieve the + following information on cursors: + + - total number of open cursors + + - size of the client cursors in current use + + - number of timed out cursors since the last server restart + + Consider the following example: + + .. code-block:: javascript + + db.runCommand( { cursorInfo: 1 } ) + + The result from the command returns the following documentation: + + .. code-block:: javascript + + { "totalOpen" : , "clientCursors_size" : , "timedOut" : , "ok" : 1 } + +.. [#queryOptions] In the :program:`mongo` shell, the cursor flags + available are: + + - ``DBQuery.Option.tailable`` + - ``DBQuery.Option.slaveOk`` + - ``DBQuery.Option.oplogReplay`` + - ``DBQuery.Option.noTimeout`` + - ``DBQuery.Option.awaitData`` + - ``DBQuery.Option.exhaust`` + - ``DBQuery.Option.partial`` + .. _read-operations-aggregation: Aggregation