Arango logo

ArangoDB v4.x is under development and not released yet.

This documentation is not final and potentially incomplete.

The cursor object of the JavaScript API

Cursor objects let you iterate over the results of executed AQL queries

The JavaScript API returns cursor objects when you use the following methods of the db object from the @arangodb module in arangosh:

  • db._query(...)
  • db._createStatement(...).execute()

Unless an error is thrown, for example due to a syntax error in the query or a runtime error during the query execution, both methods return a cursor object for a successful query. This is the case even if the result set is small enough to be transferred in a single batch, so you always interact with the results through a cursor in arangosh.

You can use the hasNext() and next() methods of the returned cursor object to iterate over the results, or call toArray() right away to get an array with all results.

If the number of query results is expected to be big, it is possible to limit the amount of documents transferred between the server and the client to a specific value. This value is called batchSize. You can set the batchSize as an option when you execute a query with db._query() or when you create a statement with db._createStatement(). If no batchSize value is specified, the server picks a reasonable default value. If the server has more documents than should be returned in a single batch, the server sets the hasMore attribute in the result. It also returns the ID of the server-side cursor in the id attribute in the response. This ID can be used with the Cursor API to fetch any outstanding results from the server and dispose the server-side cursor afterwards.

cursor.hasNext()

Checks whether there are more results available in the cursor.

If the hasNext() method returns true, then the cursor still has documents, and you can retrieve the next one with the next() method. If it returns false, the cursor is exhausted.

Example

Iterate over a query result, fetching one document at a time as long as there are more available:

var cursor = db._query("FOR x IN five RETURN x");
while (cursor.hasNext()) {
  print(cursor.next());
}
Show output
{ 
  "_key" : "74148", 
  "_id" : "five/74148", 
  "_rev" : "_l2EwrHS---", 
  "name" : "one" 
}
{ 
  "_key" : "74150", 
  "_id" : "five/74150", 
  "_rev" : "_l2EwrHS--_", 
  "name" : "two" 
}
{ 
  "_key" : "74152", 
  "_id" : "five/74152", 
  "_rev" : "_l2EwrHS--A", 
  "name" : "three" 
}
{ 
  "_key" : "74154", 
  "_id" : "five/74154", 
  "_rev" : "_l2EwrHS--B", 
  "name" : "four" 
}
{ 
  "_key" : "74156", 
  "_id" : "five/74156", 
  "_rev" : "_l2EwrHW---", 
  "name" : "five" 
}

cursor.next()

Returns the next result document.

As long as hasNext() returns true, there are more results available, and each call to next() returns a single document and advances the cursor by one position. The results are buffered locally in batches; when the current batch is exhausted and more results are available on the server, next() fetches the next batch, which requires a roundtrip to the server.

If you call next() on an exhausted cursor, then an error is thrown. To avoid this, check the availability of results with hasNext() beforehand.

Example

Get the next document of a query result:

db._query("FOR x IN five RETURN x").next();
Show output
{ 
  "_key" : "74288", 
  "_id" : "five/74288", 
  "_rev" : "_l2EwrOC---", 
  "name" : "one" 
}

cursor.toArray()

Returns all remaining result documents from the cursor as an array.

If no more results are available locally but more results are available on the server, then this method makes one or multiple roundtrips to the server to fetch them. Calling this method fully exhausts the cursor.

Example

Get all remaining documents of a query result as an array:

db._query("FOR x IN five RETURN x").toArray();
Show output
[ 
  { 
    "_key" : "74432", 
    "_id" : "five/74432", 
    "_rev" : "_l2EwrRq---", 
    "name" : "one" 
  }, 
  { 
    "_key" : "74434", 
    "_id" : "five/74434", 
    "_rev" : "_l2EwrRq--_", 
    "name" : "two" 
  }, 
  { 
    "_key" : "74436", 
    "_id" : "five/74436", 
    "_rev" : "_l2EwrRq--A", 
    "name" : "three" 
  }, 
  { 
    "_key" : "74438", 
    "_id" : "five/74438", 
    "_rev" : "_l2EwrRu---", 
    "name" : "four" 
  }, 
  { 
    "_key" : "74440", 
    "_id" : "five/74440", 
    "_rev" : "_l2EwrRu--_", 
    "name" : "five" 
  } 
]

cursor.count()

Returns the total number of documents in the result set, or undefined if the number is not available.

The number remains the same regardless of how many result documents have already been fetched from the cursor.

This method only returns a number if the cursor was created with the count cursor option enabled. Otherwise, it returns undefined.

Note that streaming cursors never return a count.

Examples

Get the total number of documents in the result set by enabling the count option:

db._query("FOR x IN 1..5 RETURN x", null, { count: true }).count();
Show output
5

If the count option is not enabled, then count() returns undefined:

Without the count option enabled, count() returns undefined:

db._query("FOR x IN 1..5 RETURN x").count();
Show output
Empty Output

cursor.getExtra()

Returns the extra data stored for the cursor, or an empty object if there is none.

The extra data can include the following attributes:

  • stats: statistics about the query execution, such as the number of scanned documents (scannedFull, scannedIndex), the number of documents written (writesExecuted), the execution time, the peak memory usage, and a fullCount value if the fullCount query option was enabled.
  • warnings: any warnings that occurred during the query execution.
  • profile: profiling information if the profile query option was enabled.

Example

Get the extra information about a query, such as execution statistics and warnings:

db._query("FOR x IN 1..5 RETURN x").getExtra();
Show output
{ 
  "warnings" : [ ], 
  "stats" : { 
    "writesExecuted" : 0, 
    "writesIgnored" : 0, 
    "documentLookups" : 0, 
    "seeks" : 0, 
    "scannedFull" : 0, 
    "scannedIndex" : 0, 
    "searchParallelism" : 1, 
    "cursorsCreated" : 0, 
    "cursorsRearmed" : 0, 
    "cacheHits" : 0, 
    "cacheMisses" : 0, 
    "filtered" : 0, 
    "httpRequests" : 0, 
    "executionTime" : 0.0002473360000010416, 
    "peakMemoryUsage" : 0, 
    "intermediateCommits" : 0 
  } 
}

cursor.cached()

Returns whether the query result was served from the AQL query results cache (true) or computed from scratch (false).

For the result of a query to be served from the cache, the query results cache needs to be enabled and the same query needs to have been executed and cached before.

Example

Check whether the query result was served from the query results cache:

db._query("FOR x IN 1..5 RETURN x", null, null, { cache: true }).cached();
db._query("FOR x IN 1..5 RETURN x", null, null, { cache: true }).cached();
Show output
false

true

cursor.stream()

Returns whether the cursor is a streaming cursor (true) or not (false).

With a streaming cursor, the query is executed lazily as you fetch results, instead of computing the full result set upfront. You can request a streaming cursor with the stream query option.

Example

Check whether the cursor is a streaming cursor:

db._query("FOR x IN 1..5 RETURN x", null, null, { stream: true }).stream();
Show output
true

cursor.retriable()

Returns whether the cursor is retriable (true) or not (false).

If a cursor is retriable, then fetching the next batch of results from the server can be retried in case a previous fetch attempt failed, without skipping or losing any results. You can request a retriable cursor with the allowRetry query option.

Example

Check whether the fetching of result batches from the cursor can be retried:

db._query("FOR x IN 1..5 RETURN x", null, null, { allowRetry: true }).retriable();
Show output
true

cursor.dispose()

Disposes the cursor and its results.

If you are no longer interested in any further results, you should call dispose() in order to free any resources associated with the cursor. If a server-side cursor still exists because not all batches have been fetched, calling dispose() deletes it on the server, which requires a roundtrip. After calling dispose(), you can no longer access the cursor.

Example

Dispose of a cursor to free the resources associated with it:

var cursor = db._query("FOR x IN 1..5 RETURN x");
cursor.dispose();
Show output
Empty Output

cursor.toString()

Returns a string representation of the cursor.

The string representation includes metadata about the cursor, such as the cursor id, the count (for non-streaming cursors), whether the results were cached, whether more results are available, and any warnings. It also prints up to the first ten result documents. In arangosh, this is the representation that is shown for a cursor that is not assigned to a variable.

Example

Get a string representation of the cursor:

db._query("FOR x IN 1..5 RETURN x").toString();
Show output
[object ArangoQueryCursor, count: 5, results cached: false, hasMore: false]

[ 
  1, 
  2, 
  3, 
  4, 
  5 
]

cursor.data

The raw result data object as returned by the server.

This attribute holds the underlying server response for the current batch, including the following attributes:

  • result: the documents of the currently loaded batch.
  • hasMore: whether more results are available on the server.
  • id: the identifier of the server-side cursor (if any).
  • count: the total number of documents (if the count option was enabled).
  • cached: whether the result was served from the query results cache.
  • extra: extra data such as statistics and warnings (see getExtra()).

Prefer the methods described above over accessing this attribute directly, as the raw data is subject to change.

Example

Access the raw result data object as returned by the server:

db._query("FOR x IN 1..5 RETURN x").data;
Show output
{ 
  "result" : [ 
    1, 
    2, 
    3, 
    4, 
    5 
  ], 
  "hasMore" : false, 
  "cached" : false, 
  "extra" : { 
    "warnings" : [ ], 
    "stats" : { 
      "writesExecuted" : 0, 
      "writesIgnored" : 0, 
      "documentLookups" : 0, 
      "seeks" : 0, 
      "scannedFull" : 0, 
      "scannedIndex" : 0, 
      "searchParallelism" : 1, 
      "cursorsCreated" : 0, 
      "cursorsRearmed" : 0, 
      "cacheHits" : 0, 
      "cacheMisses" : 0, 
      "filtered" : 0, 
      "httpRequests" : 0, 
      "executionTime" : 0.00018785000000320906, 
      "peakMemoryUsage" : 0, 
      "intermediateCommits" : 0 
    } 
  }, 
  "code" : 201 
}