Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions source/includes/read/cursors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.example
import com.mongodb.ConnectionString
import com.mongodb.CursorType
import com.mongodb.MongoClientSettings
import com.mongodb.client.model.Filters.eq
import com.mongodb.kotlin.client.MongoClient
import org.bson.codecs.pojo.annotations.BsonId
import org.bson.types.ObjectId

// start-data-class
data class Restaurant(
@BsonId
val id: ObjectId,
val name: String
)
// end-data-class

fun main() {
val uri = "<connection string URI>"

val settings = MongoClientSettings.builder()
.applyConnectionString(ConnectionString(uri))
.retryWrites(true)
.build()

val mongoClient = MongoClient.create(settings)
val database = mongoClient.getDatabase("sample_restaurants")
val collection = database.getCollection<Restaurant>("restaurants")

// start-cursor-iterate
val results = collection.find()

results.forEach { result ->
println(results)
}
// end-cursor-iterate

// start-cursor-next
val results = collection.find<Restaurant>(eq(Restaurant::name.name, "Dunkin' Donuts"))

println(results.cursor().next())
// end-cursor-next

// start-cursor-list
val results = collection.find<Restaurant>(eq(Restaurant::name.name, "Dunkin' Donuts"))
val resultsList = results.toList()

for (result in resultsList) {
println(result)
}
// end-cursor-list

// start-cursor-close
val results = collection.find<Restaurant>()

// Handle your results here

results.cursor().close()
// end-cursor-close

// start-tailable-cursor
val results = collection.find<Restaurant>().cursorType(CursorType.TailableAwait)
// end-tailable-cursor
}

1 change: 1 addition & 0 deletions source/read.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Read Data from MongoDB
/read/project
/read/specify-documents-to-return
/read/count
/read/cursors

Overview
--------
Expand Down
171 changes: 171 additions & 0 deletions source/read/cursors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
.. _kotlin-sync-cursors:

=========================
Access Data From a Cursor
=========================

.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: read, results, oplog

Overview
--------

In this guide, you can learn how to access data from a **cursor** with the
{+driver-short+}.

A cursor is a mechanism that returns the results of a read operation in iterable
batches. Because a cursor holds only a subset of documents at any given time,
cursors reduce both memory consumption and network bandwidth usage.

Whenever the {+driver-short+} performs a read operation that returns multiple
documents, it automatically returns those documents in a cursor.

Sample Data
~~~~~~~~~~~

The examples in this guide use the ``restaurants`` collection in the ``sample_restaurants``
database from the :atlas:`Atlas sample datasets </sample-data>`. To learn how to create a
free MongoDB Atlas cluster and load the sample datasets, see the
:atlas:`Get Started with Atlas </getting-started>` guide.

The following {+language+} data class models the documents in this collection:

.. literalinclude:: /includes/read/cursors.kt
:start-after: start-data-class
:end-before: end-data-class
:language: kotlin
:copyable:

.. _kotlin-sync-cursors-iterate:

Access Cursor Contents Iteratively
----------------------------------

To iterate over the contents of a cursor, use the ``forEach()`` method, as shown in the
following example:

.. literalinclude:: /includes/read/cursors.kt
:start-after: start-cursor-iterate
:end-before: end-cursor-iterate
:language: kotlin
:copyable:
:dedent:

Retrieve Documents Individually
-------------------------------

Retrieve documents from a cursor individually by calling the ``next()`` method.

The following example finds all documents in a collection with a ``name`` value
of ``"Dunkin' Donuts"``. It then prints the first document in the cursor by calling the
``next()`` method.

.. io-code-block::
:copyable:

.. input:: /includes/read/cursors.kt
:start-after: start-cursor-next
:end-before: end-cursor-next
:language: kotlin
:dedent:

.. output::
:visible: false

Restaurant(id=5eb3d668b31de5d588f42c66, name=Dunkin' Donuts)

Retrieve All Documents
----------------------

.. warning::

If the number and size of documents returned by your query exceeds available
application memory, your program will crash. If you expect a large result
set, :ref:`access your cursor iteratively <kotlin-sync-cursors-iterate>`.

To retrieve all documents from a cursor, convert the cursor into a ``List`` as
shown in the following example:

.. io-code-block::
:copyable:

.. input:: /includes/read/cursors.kt
:start-after: start-cursor-list
:end-before: end-cursor-list
:language: kotlin
:dedent:

.. output::
:visible: false

Restaurant(id=5eb3d668b31de5d588f42c66, name=Dunkin' Donuts)
Restaurant(id=5eb3d668b31de5d588f42ca0, name=Dunkin' Donuts)
Restaurant(id=5eb3d668b31de5d588f42b08, name=Dunkin' Donuts)
Restaurant(id=5eb3d668b31de5d588f42cd7, name=Dunkin' Donuts)
...

Close a Cursor
--------------

By default, MongoDB closes a cursor when the client has exhausted all the
results in the cursor. To explicitly close a cursor, call the ``close()`` method
as shown in the following example:

.. literalinclude:: /includes/read/cursors.kt
:start-after: start-cursor-close
:end-before: end-cursor-close
:language: kotlin
:copyable:
:dedent:

Tailable Cursors
----------------

When querying on a :manual:`capped collection </core/capped-collections/>`, you
can use a **tailable cursor** that remains open after the client exhausts the
results in a cursor. To create a tailable cursor with capped collection,
specify ``CursorType.TailableAwait`` to the ``cursorType`` method of a
``FindIterable`` object.

The following example creates a tailable cursor on a collection:

.. literalinclude:: /includes/read/cursors.kt
:start-after: start-tailable-cursor
:end-before: end-tailable-cursor
:language: kotlin
:copyable:
:dedent:

To learn more about tailable cursors and their usage, see the :manual:`Tailable Cursors guide
</core/tailable-cursors/>` in the {+mdb-server+} manual.

Troubleshooting
---------------

"*CursorNotFound* cursor id not valid at server"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Cursors in MongoDB can timeout on the server if they've been open for
a long time without any operations being performed on them. This can
lead to a ``CursorNotFound`` exception when you try to iterate through the cursor.

API Documentation
-----------------

To learn more about any of the methods or types discussed in this
guide, see the following API documentation:

- `find() <{+api+}/mongodb-driver-kotlin-sync/com.mongodb.kotlin.client/-mongo-collection/find.html>`__
- `FindIterable <{+api+}/mongodb-driver-kotlin-sync/com.mongodb.kotlin.client/-find-iterable/index.html>`__
- `MongoCursor <{+api+}/mongodb-driver-kotlin-sync/com.mongodb.kotlin.client/-mongo-cursor/index.html>`__
- `CursorType <{+core-api+}/com/mongodb/CursorType.html>`__