From 7567b9a7d4ceef3e6f7361a2d3099e2a54d11625 Mon Sep 17 00:00:00 2001 From: kay Date: Fri, 7 Dec 2012 12:20:21 -0500 Subject: [PATCH 1/5] DOCS-674 migrate tailable cursor page --- source/applications.txt | 1 + source/tutorial/create-tailable-cursor.txt | 254 +++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 source/tutorial/create-tailable-cursor.txt diff --git a/source/applications.txt b/source/applications.txt index 231826f8fb2..9aa476af39e 100644 --- a/source/applications.txt +++ b/source/applications.txt @@ -57,4 +57,5 @@ The following documents provide patterns for developing application features: tutorial/isolate-sequence-of-operations tutorial/create-an-auto-incrementing-field tutorial/expire-data + tutorial/create-tailable-cursor diff --git a/source/tutorial/create-tailable-cursor.txt b/source/tutorial/create-tailable-cursor.txt new file mode 100644 index 00000000000..2b10185fbcd --- /dev/null +++ b/source/tutorial/create-tailable-cursor.txt @@ -0,0 +1,254 @@ +====================== +Create Tailable Cursor +====================== + +.. default-domain:: mongodb + +Overview +-------- + +By default, MongoDB will automatically close a cursor if the cursor has +been exhausted. However, with :doc:`capped collections +`, you can create a *Tailable Cursor* which +remains open after the cursor has been exhausted. Similar to the Unix +``tail -f`` command, the tailable cursor "tails" the end of a capped +collection. After new documents are inserted into the capped +collection, you can use the tailable cursor to continue retrieving +documents. + +If you query on an indexed field, do not use tailable cursors, but +instead, use a regular cursor. Keep track of the last value of the +indexed field returned by the query. To retrieve the newly added +documents, query the table again using the last value of the indexed +field in the query criteria, as in the following example: + +.. code-block:: javascript + + db.mycollection.find( { indexedField: { $gt: } } ) + +Use tailable cursors on capped collections with high number of write +operations for which an index would be too expensive. For instance, +MongoDB :doc:`replication ` uses tailable cursors to +tail the primary's :term:`oplog`. + +Consider the following behaviors related to tailable cursors: + +- Tailable cursors do not use indexes and return documents in + :term:`natural order`. + +- Because tailable cursors do not use indexes, the initial table scan + for the query may be expensive; however, subsequent retrievals of the + newly added documents are inexpensive. + +- Tailable cursors may become *dead* if either: + + - the query returned no match. + + - the last returned object is at the end of the collection and is + deleted. + + A *dead* cursor has an id of ``0``. + +See your :doc:`driver documentation ` for +driver-specific method to specify the tailable cursor as well as +:wiki:`wire protocol ` for more information on +wire protocols. + +JavaScript Example +------------------ + +The JavaScript example uses a tailable cursor to output the results +from a query of a capped collection named ``myCappedCollection``: + +.. code-block:: javascript + + var coll = db.myCappedCollection; + + var startDoc = coll.find().sort( { '$natural': 1 } ).limit(1).next(); + var lastValue = startDoc['insertDate']; + printjson(startDoc) + + while (1) { + + var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ).sort( { '$natural': 1 } ); + + cursor.addOption( 2 ); + + cursor.addOption( 32 ); + + while (1) { + + if ( cursor.hasNext() ) { + var doc = cursor.next(); + lastValue = doc['insertDate']; + printjson(doc); + } + } + + } + +The example performs the following actions: + +- Query the capped collection to access the first document inserted. + The query specifies the ``$natural`` sort order to use the insertion + order for capped-collections. + +- Initialize the ``lastValue`` variable to hold the last accessed value + of the unindexed field ``insertDate``. Newly added documents contain + increasing values for the ``insertDate`` field. + +- In an outer ``while (1)`` loop, + + - Query the capped collection for documents with the field + ``insertDate`` greater than the ``lastValue``. + + - Add the :wiki:`tailableCursor wire protocol ` + option to the cursor to specify that the return cursor should be a + tailable cursor. In the :program:`mongo` shell, protocol option is + ``2`` (i.e. bitwise shift of 1): + + .. code-block:: javascript + + cursor.addOption( 2 ); + + See your :doc:`driver documentation ` for + driver-specific method to specify the tailable cursor wire protocol. + + - Add the :wiki:`awaitData wire protocol ` + option to the cursor to specify that the cursor should block for a + few seconds to wait for data. In the :program:`mongo` shell, the + protocol is ``32`` (i.e. bitwise shift of 5): + + .. code-block:: javascript + + cursor.addOption( 32 ); + + See your :doc:`driver documentation ` for + driver-specific method to specify the await data wire protocol. + + - In an inner ``while (1)`` loop, + + - If the cursor has documents, + + - retrieve the document, + + - update the ``lastValue`` variable, + + - print the document, + + - and loop the inner ``while (1)`` loop to recheck for more + documents. + + - Else do nothing and repeat the inner ``while (1)`` loop to + recheck for more documents. + +C++ Example +----------- + +The ``tail`` function uses a tailable cursor to output the results from +a query of a capped collection. The function also handles the case of +the dead cursor: + +.. code-block:: cpp + + #include "client/dbclient.h" + + using namespace mongo; + + /* + * Example of a tailable cursor. + * The function "tails" the capped collection (ns) and output elements as they are added. + * The function also handles the possibility of a dead cursor by tracking the field 'insertDate'. + * New documents are added with increasing values of 'insertDate'. + */ + + void tail(DBClientBase& conn, const char *ns) { + + BSONElement lastValue = minKey.firstElement(); + + Query query = Query().sort("$natural"); + + while ( 1 ) { + auto_ptr c = + conn.query(ns, query, 0, 0, 0, + QueryOption_CursorTailable | QueryOption_AwaitData ); + + while ( 1 ) { + if ( !c->more() ) { + + if ( c->isDead() ) { + break; + } + + continue; + } + + BSONObj o = c->next(); + lastValue = o["insertDate"]; + cout << o.toString() << endl; + } + + query = QUERY( "insertDate" << GT << lastValue ).sort("$natural"); + } + } + +The ``tail`` function performs the following actions: + +- Initialize the ``lastValue`` variable, which tracks the last accessed + value and will be used if the cursor becomes *dead* and we need to + requery. + +- Specify ``sort("$natural")`` to use the insertion order for + capped-collections. + +- In an outer ``while(1)`` loop, + + - Query the capped collection and return a tailable cursor that + blocks for several seconds waiting for new documents + + .. code-block:: cpp + + auto_ptr c = + conn.query(ns, query, 0, 0, 0, + QueryOption_CursorTailable | QueryOption_AwaitData ); + + - The capped collection is specified by ``ns`` and is an argument + to the function. + + - The function sets the ``QueryOption_CursorTailable`` :wiki:`wire + protocol ` option to specify that the + returned cursor is a tailable cursor. + + - The function sets the ``QueryOption_AwaitData`` :wiki:`wire + protocol ` option to specify that the + returned cursor should block for a few seconds to wait for data. + + - In an inner ``while (1)`` loop, read the documents from the cursor: + + - If the cursor has no more documents and is not dead, loop the + inner ``while`` loop to recheck for more documents. + + - If the cursor has no more documents and is dead, break the inner + ``while`` loop. + + - If the cursor has documents, + + - output the document, + + - update the ``lastValue`` value, + + - and loop the inner ``while (1)`` loop to recheck for more + documents. + + - If the logic breaks out of the inner ``while (1)`` loop (i.e. the + cursor is dead): + + - Use the ``lastValue`` value to create a new query condition that + matches documents added after the ``lastValue``: + + .. code-block:: cpp + + query = QUERY( "insertDate" << GT << lastValue ).sort("$natural"); + + - Loop the outer ``while (1)`` loop to re-query with the new query + condition and repeat. From b0f1826737dab89ca53e14c273aa0533a6df145a Mon Sep 17 00:00:00 2001 From: kay Date: Thu, 13 Dec 2012 23:28:14 -0500 Subject: [PATCH 2/5] DOCS-674 tailable cursor incorporate ed and scott's comments --- source/core/capped-collections.txt | 12 +++ source/tutorial/create-tailable-cursor.txt | 90 ++++++++++------------ 2 files changed, 54 insertions(+), 48 deletions(-) diff --git a/source/core/capped-collections.txt b/source/core/capped-collections.txt index df6efbb9a54..c9c53454028 100644 --- a/source/core/capped-collections.txt +++ b/source/core/capped-collections.txt @@ -161,3 +161,15 @@ value of a date-typed field and a TTL value for the index. :doc:`TTL Collections ` are not compatible with capped collections. + +Tailable Cursor +~~~~~~~~~~~~~~~ + +You can use a tailable cursor with capped collections. Similar to the +Unix ``tail -f`` command, the tailable cursor "tails" the end of a +capped collection. As new documents are inserted into the capped +collection, you can use the tailable cursor to continue retrieving +documents. + +See :doc:`/tutorial/create-tailable-cursor` for information on creating +a tailable cursor. diff --git a/source/tutorial/create-tailable-cursor.txt b/source/tutorial/create-tailable-cursor.txt index 2b10185fbcd..a4fd2c88877 100644 --- a/source/tutorial/create-tailable-cursor.txt +++ b/source/tutorial/create-tailable-cursor.txt @@ -16,31 +16,31 @@ collection. After new documents are inserted into the capped collection, you can use the tailable cursor to continue retrieving documents. -If you query on an indexed field, do not use tailable cursors, but +Use tailable cursors on capped collections with high numbers of write +operations for which an index would be too expensive. For instance, +MongoDB :doc:`replication ` uses tailable cursors to +tail the primary's :term:`oplog`. + +If your query is on an indexed field, do not use tailable cursors, but instead, use a regular cursor. Keep track of the last value of the indexed field returned by the query. To retrieve the newly added -documents, query the table again using the last value of the indexed -field in the query criteria, as in the following example: +documents, query the collection again using the last value of the +indexed field in the query criteria, as in the following example: .. code-block:: javascript db.mycollection.find( { indexedField: { $gt: } } ) -Use tailable cursors on capped collections with high number of write -operations for which an index would be too expensive. For instance, -MongoDB :doc:`replication ` uses tailable cursors to -tail the primary's :term:`oplog`. - Consider the following behaviors related to tailable cursors: - Tailable cursors do not use indexes and return documents in :term:`natural order`. -- Because tailable cursors do not use indexes, the initial table scan - for the query may be expensive; however, subsequent retrievals of the - newly added documents are inexpensive. +- Because tailable cursors do not use indexes, the initial scan for the + query may be expensive; but, after initially exhausting the cursor, + subsequent retrievals of the newly added documents are inexpensive. -- Tailable cursors may become *dead* if either: +- Tailable cursors may become *dead*, or invalid, if either: - the query returned no match. @@ -49,10 +49,13 @@ Consider the following behaviors related to tailable cursors: A *dead* cursor has an id of ``0``. -See your :doc:`driver documentation ` for -driver-specific method to specify the tailable cursor as well as -:wiki:`wire protocol ` for more information on -wire protocols. +See your :doc:`driver documentation ` for the +driver-specific method to specify the tailable cursor. +[#tailable-cursor-wire-protocol]_ + +.. [#tailable-cursor-wire-protocol] For more information on the details + of specifying a tailable cursor, see :wiki:`wire protocol `. JavaScript Example ------------------ @@ -70,11 +73,11 @@ from a query of a capped collection named ``myCappedCollection``: while (1) { - var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ).sort( { '$natural': 1 } ); + var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ); - cursor.addOption( 2 ); + cursor.addOption( DBQuery.Option.tailable ); - cursor.addOption( 32 ); + cursor.addOption( DBQuery.Option.awaitData ); while (1) { @@ -84,7 +87,6 @@ from a query of a capped collection named ``myCappedCollection``: printjson(doc); } } - } The example performs the following actions: @@ -102,29 +104,25 @@ The example performs the following actions: - Query the capped collection for documents with the field ``insertDate`` greater than the ``lastValue``. - - Add the :wiki:`tailableCursor wire protocol ` - option to the cursor to specify that the return cursor should be a - tailable cursor. In the :program:`mongo` shell, protocol option is - ``2`` (i.e. bitwise shift of 1): + - Specify that the returned cursor should be a tailable cursor: .. code-block:: javascript - cursor.addOption( 2 ); + cursor.addOption( DBQuery.Option.tailable ); See your :doc:`driver documentation ` for - driver-specific method to specify the tailable cursor wire protocol. + the driver-specific method to specify a tailable cursor. - - Add the :wiki:`awaitData wire protocol ` - option to the cursor to specify that the cursor should block for a - few seconds to wait for data. In the :program:`mongo` shell, the - protocol is ``32`` (i.e. bitwise shift of 5): + - Specify that the cursor should block for a few seconds to wait for + data: .. code-block:: javascript - cursor.addOption( 32 ); + cursor.addOption( DBQuery.Option.awaitData ); See your :doc:`driver documentation ` for - driver-specific method to specify the await data wire protocol. + the driver-specific method to specify that the cursor should wait + for data. - In an inner ``while (1)`` loop, @@ -136,8 +134,8 @@ The example performs the following actions: - print the document, - - and loop the inner ``while (1)`` loop to recheck for more - documents. + - and loop through the inner ``while (1)`` loop to recheck for + more documents. - Else do nothing and repeat the inner ``while (1)`` loop to recheck for more documents. @@ -146,7 +144,7 @@ C++ Example ----------- The ``tail`` function uses a tailable cursor to output the results from -a query of a capped collection. The function also handles the case of +a query to a capped collection. The function also handles the case of the dead cursor: .. code-block:: cpp @@ -166,7 +164,7 @@ the dead cursor: BSONElement lastValue = minKey.firstElement(); - Query query = Query().sort("$natural"); + Query query = Query(); while ( 1 ) { auto_ptr c = @@ -188,7 +186,7 @@ the dead cursor: cout << o.toString() << endl; } - query = QUERY( "insertDate" << GT << lastValue ).sort("$natural"); + query = QUERY( "insertDate" << GT << lastValue ); } } @@ -198,9 +196,6 @@ The ``tail`` function performs the following actions: value and will be used if the cursor becomes *dead* and we need to requery. -- Specify ``sort("$natural")`` to use the insertion order for - capped-collections. - - In an outer ``while(1)`` loop, - Query the capped collection and return a tailable cursor that @@ -215,13 +210,12 @@ The ``tail`` function performs the following actions: - The capped collection is specified by ``ns`` and is an argument to the function. - - The function sets the ``QueryOption_CursorTailable`` :wiki:`wire - protocol ` option to specify that the - returned cursor is a tailable cursor. + - The function sets the ``QueryOption_CursorTailable`` option to + specify that the returned cursor is a tailable cursor. - - The function sets the ``QueryOption_AwaitData`` :wiki:`wire - protocol ` option to specify that the - returned cursor should block for a few seconds to wait for data. + - The function sets the ``QueryOption_AwaitData`` option to specify + that the returned cursor should block for a few seconds to wait + for data. - In an inner ``while (1)`` loop, read the documents from the cursor: @@ -248,7 +242,7 @@ The ``tail`` function performs the following actions: .. code-block:: cpp - query = QUERY( "insertDate" << GT << lastValue ).sort("$natural"); + query = QUERY( "insertDate" << GT << lastValue ); - - Loop the outer ``while (1)`` loop to re-query with the new query + - Loop through the outer ``while (1)`` loop to re-query with the new query condition and repeat. From 5b06203f47874d169cd7fc64ee211494e4621193 Mon Sep 17 00:00:00 2001 From: kay Date: Fri, 14 Dec 2012 00:39:58 -0500 Subject: [PATCH 3/5] DOCS-674 tailable cursor incorporate ed and scott's comments --- source/tutorial/create-tailable-cursor.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/tutorial/create-tailable-cursor.txt b/source/tutorial/create-tailable-cursor.txt index a4fd2c88877..ba3b593aa67 100644 --- a/source/tutorial/create-tailable-cursor.txt +++ b/source/tutorial/create-tailable-cursor.txt @@ -61,7 +61,9 @@ JavaScript Example ------------------ The JavaScript example uses a tailable cursor to output the results -from a query of a capped collection named ``myCappedCollection``: +from a query of a capped collection named ``myCappedCollection``. To +periodically check for new data, the ``cursor->hasNext()`` statement is +inside a loop: .. code-block:: javascript @@ -144,8 +146,9 @@ C++ Example ----------- The ``tail`` function uses a tailable cursor to output the results from -a query to a capped collection. The function also handles the case of -the dead cursor: +a query to a capped collection. The function handles the case of the +dead cursor by having the query be inside a loop. To periodically check +for new data, the ``cursor->more()`` statement is also inside a loop: .. code-block:: cpp From f39cd3977983c1bf0a7b18c5ac52a2ed01070c30 Mon Sep 17 00:00:00 2001 From: kay Date: Thu, 20 Dec 2012 13:59:47 -0500 Subject: [PATCH 4/5] DOCS-674 tailable cursor final edit after scott and tyler --- source/tutorial/create-tailable-cursor.txt | 190 ++++++++++----------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/source/tutorial/create-tailable-cursor.txt b/source/tutorial/create-tailable-cursor.txt index ba3b593aa67..f7578fbccee 100644 --- a/source/tutorial/create-tailable-cursor.txt +++ b/source/tutorial/create-tailable-cursor.txt @@ -54,101 +54,20 @@ driver-specific method to specify the tailable cursor. [#tailable-cursor-wire-protocol]_ .. [#tailable-cursor-wire-protocol] For more information on the details - of specifying a tailable cursor, see :wiki:`wire protocol `. - -JavaScript Example ------------------- - -The JavaScript example uses a tailable cursor to output the results -from a query of a capped collection named ``myCappedCollection``. To -periodically check for new data, the ``cursor->hasNext()`` statement is -inside a loop: - -.. code-block:: javascript - - var coll = db.myCappedCollection; - - var startDoc = coll.find().sort( { '$natural': 1 } ).limit(1).next(); - var lastValue = startDoc['insertDate']; - printjson(startDoc) - - while (1) { - - var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ); - - cursor.addOption( DBQuery.Option.tailable ); - - cursor.addOption( DBQuery.Option.awaitData ); - - while (1) { - - if ( cursor.hasNext() ) { - var doc = cursor.next(); - lastValue = doc['insertDate']; - printjson(doc); - } - } - } - -The example performs the following actions: - -- Query the capped collection to access the first document inserted. - The query specifies the ``$natural`` sort order to use the insertion - order for capped-collections. - -- Initialize the ``lastValue`` variable to hold the last accessed value - of the unindexed field ``insertDate``. Newly added documents contain - increasing values for the ``insertDate`` field. - -- In an outer ``while (1)`` loop, - - - Query the capped collection for documents with the field - ``insertDate`` greater than the ``lastValue``. - - - Specify that the returned cursor should be a tailable cursor: - - .. code-block:: javascript - - cursor.addOption( DBQuery.Option.tailable ); - - See your :doc:`driver documentation ` for - the driver-specific method to specify a tailable cursor. - - - Specify that the cursor should block for a few seconds to wait for - data: - - .. code-block:: javascript - - cursor.addOption( DBQuery.Option.awaitData ); - - See your :doc:`driver documentation ` for - the driver-specific method to specify that the cursor should wait - for data. - - - In an inner ``while (1)`` loop, - - - If the cursor has documents, - - - retrieve the document, - - - update the ``lastValue`` variable, - - - print the document, - - - and loop through the inner ``while (1)`` loop to recheck for - more documents. - - - Else do nothing and repeat the inner ``while (1)`` loop to - recheck for more documents. + of specifying a tailable cursor, see :wiki:`Mongo wire protocol ` documentation. C++ Example ----------- The ``tail`` function uses a tailable cursor to output the results from -a query to a capped collection. The function handles the case of the -dead cursor by having the query be inside a loop. To periodically check -for new data, the ``cursor->more()`` statement is also inside a loop: +a query to a capped collection: + +- The function handles the case of the dead cursor by having the query + be inside a loop. + +- To periodically check for new data, the ``cursor->more()`` statement + is also inside a loop. .. code-block:: cpp @@ -167,7 +86,7 @@ for new data, the ``cursor->more()`` statement is also inside a loop: BSONElement lastValue = minKey.firstElement(); - Query query = Query(); + Query query = Query().hint( BSON( "$natural" << 1 ) ); while ( 1 ) { auto_ptr c = @@ -189,7 +108,7 @@ for new data, the ``cursor->more()`` statement is also inside a loop: cout << o.toString() << endl; } - query = QUERY( "insertDate" << GT << lastValue ); + query = QUERY( "insertDate" << GT << lastValue ).hint( BSON( "$natural" << 1 ) ); } } @@ -197,7 +116,7 @@ The ``tail`` function performs the following actions: - Initialize the ``lastValue`` variable, which tracks the last accessed value and will be used if the cursor becomes *dead* and we need to - requery. + requery. Use ``hint()`` to ensure that the ``$natural`` order is used. - In an outer ``while(1)`` loop, @@ -241,11 +160,92 @@ The ``tail`` function performs the following actions: cursor is dead): - Use the ``lastValue`` value to create a new query condition that - matches documents added after the ``lastValue``: + matches documents added after the ``lastValue``. Explicitly + ensure ``$natural`` order with the ``hint()`` method: .. code-block:: cpp - query = QUERY( "insertDate" << GT << lastValue ); + query = QUERY( "insertDate" << GT << lastValue ).hint( BSON( "$natural" << 1 ) ); - Loop through the outer ``while (1)`` loop to re-query with the new query condition and repeat. + +JavaScript Example +------------------ + +The JavaScript example uses a tailable cursor to output the results +from a query of a capped collection named ``myCappedCollection``. To +periodically check for new data, the ``cursor->hasNext()`` statement is +inside a loop: + +.. code-block:: javascript + + var coll = db.myCappedCollection; + + var startDoc = coll.find().hint( { '$natural': 1 } ).limit(1).next(); + var lastValue = startDoc['insertDate']; + printjson(startDoc) + + while (1) { + + var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ).hint( { '$natural': 1 } ); + + cursor.addOption( DBQuery.Option.tailable ); + + cursor.addOption( DBQuery.Option.awaitData ); + + while ( cursor.hasNext() ) { + var doc = cursor.next(); + lastValue = doc['insertDate']; + printjson(doc); + } + } + +The example performs the following actions: + +- Query the capped collection to access the first document inserted. + The query uses the :method:`hint() ` method to ensure + the use of the insertion order. + +- Initialize the ``lastValue`` variable to hold the last accessed value + of the unindexed field ``insertDate``. Newly added documents contain + increasing values for the ``insertDate`` field. + +- In an outer ``while (1)`` loop, + + - Query the capped collection for documents with the field + ``insertDate`` greater than the ``lastValue``. The query uses the + :method:`hint() ` method to ensure that the + insertion order is used. + + - Specify that the returned cursor should be a tailable cursor: + + .. code-block:: javascript + + cursor.addOption( DBQuery.Option.tailable ); + + See your :doc:`driver documentation ` for + the driver-specific method to specify a tailable cursor. + + - Specify that the cursor should block for a few seconds to wait for + data: + + .. code-block:: javascript + + cursor.addOption( DBQuery.Option.awaitData ); + + See your :doc:`driver documentation ` for + the driver-specific method to specify that the cursor should wait + for data. + + - In an inner ``while (cursor.hasNext())`` loop, + + - retrieve the document, + + - update the ``lastValue`` variable, + + - print the document, + + - and loop to recheck for more documents. + + - If there are no more documents, repeat the outer loop. From 9e8de2751d8a202d5d5fc496ee0f4aecd8f2ce8d Mon Sep 17 00:00:00 2001 From: kay Date: Thu, 20 Dec 2012 14:36:00 -0500 Subject: [PATCH 5/5] DOCS-674 tailable cursor final edit after scott - removing javascript example --- source/tutorial/create-tailable-cursor.txt | 81 +--------------------- 1 file changed, 3 insertions(+), 78 deletions(-) diff --git a/source/tutorial/create-tailable-cursor.txt b/source/tutorial/create-tailable-cursor.txt index f7578fbccee..00128956d3f 100644 --- a/source/tutorial/create-tailable-cursor.txt +++ b/source/tutorial/create-tailable-cursor.txt @@ -170,82 +170,7 @@ The ``tail`` function performs the following actions: - Loop through the outer ``while (1)`` loop to re-query with the new query condition and repeat. -JavaScript Example ------------------- +.. seealso:: -The JavaScript example uses a tailable cursor to output the results -from a query of a capped collection named ``myCappedCollection``. To -periodically check for new data, the ``cursor->hasNext()`` statement is -inside a loop: - -.. code-block:: javascript - - var coll = db.myCappedCollection; - - var startDoc = coll.find().hint( { '$natural': 1 } ).limit(1).next(); - var lastValue = startDoc['insertDate']; - printjson(startDoc) - - while (1) { - - var cursor = coll.find( { 'insertDate' : { '$gt' : lastValue } } ).hint( { '$natural': 1 } ); - - cursor.addOption( DBQuery.Option.tailable ); - - cursor.addOption( DBQuery.Option.awaitData ); - - while ( cursor.hasNext() ) { - var doc = cursor.next(); - lastValue = doc['insertDate']; - printjson(doc); - } - } - -The example performs the following actions: - -- Query the capped collection to access the first document inserted. - The query uses the :method:`hint() ` method to ensure - the use of the insertion order. - -- Initialize the ``lastValue`` variable to hold the last accessed value - of the unindexed field ``insertDate``. Newly added documents contain - increasing values for the ``insertDate`` field. - -- In an outer ``while (1)`` loop, - - - Query the capped collection for documents with the field - ``insertDate`` greater than the ``lastValue``. The query uses the - :method:`hint() ` method to ensure that the - insertion order is used. - - - Specify that the returned cursor should be a tailable cursor: - - .. code-block:: javascript - - cursor.addOption( DBQuery.Option.tailable ); - - See your :doc:`driver documentation ` for - the driver-specific method to specify a tailable cursor. - - - Specify that the cursor should block for a few seconds to wait for - data: - - .. code-block:: javascript - - cursor.addOption( DBQuery.Option.awaitData ); - - See your :doc:`driver documentation ` for - the driver-specific method to specify that the cursor should wait - for data. - - - In an inner ``while (cursor.hasNext())`` loop, - - - retrieve the document, - - - update the ``lastValue`` variable, - - - print the document, - - - and loop to recheck for more documents. - - - If there are no more documents, repeat the outer loop. + `Detailed blog post on tailable cursor + `_