Spring data mongodb - The 'cursor' option is required

Viewed 37577

I am trying to execute an aggregate operation using Spring Data MongoDB 3.6-rc4.

Aggregation agg = newAggregation(
    lookup("orders", "orderId", "_id", "order") 
);
List<BasicDBObject> results = mongoOperations.aggregate(agg, "transactions", BasicDBObject.class).getMappedResults();

But get the following error on running the query

2017-11-24 17:03:41,539 WARN  org.springframework.data.mongodb.core.MongoTemplate : Command execution of { "aggregate" : "transactions" , "pipeline" : [ { "$lookup" : { "from" : "orders" , "localField" : "orderId" , "foreignField" : "_id" , "as" : "order"}}]} failed: The 'cursor' option is required, except for aggregate with the explain argument
2017-11-24 17:03:41,574 ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: Command execution failed:  Error [The 'cursor' option is required, except for aggregate with the explain argument], Command = { "aggregate" : "transactions" , "pipeline" : [ { "$lookup" : { "from" : "orders" , "localField" : "orderId" , "foreignField" : "_id" , "as" : "order"}}]}; nested exception is com.mongodb.MongoCommandException: Command failed with error 9: 'The 'cursor' option is required, except for aggregate with the explain argument' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "The 'cursor' option is required, except for aggregate with the explain argument", "code" : 9, "codeName" : "FailedToParse" }] with root cause
com.mongodb.MongoCommandException: Command failed with error 9: 'The 'cursor' option is required, except for aggregate with the explain argument' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "The 'cursor' option is required, except for aggregate with the explain argument", "code" : 9, "codeName" : "FailedToParse" }
    at com.mongodb.CommandResult.getException(CommandResult.java:80) ~[mongo-java-driver-3.5.0.jar:na]
    at com.mongodb.CommandResult.throwOnError(CommandResult.java:94) ~[mongo-java-driver-3.5.0.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.handleCommandError(MongoTemplate.java:2100) ~[spring-data-mongodb-1.10.8.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1577) ~[spring-data-mongodb-1.10.8.RELEASE.jar:na]
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1505) ~[spring-data-mongodb-1.10.8.RELEASE.jar:na]

Thanks in advance!!

13 Answers

MongoDB changed in 3.6 how the aggregation command works. Aggregations require now a cursor. We adapted Spring Data MongoDB 2.1 but not previous versions.

Aggregations must be invoked through the collection's aggregate(…) method instead of calling the command directly. This is also the reason why we didn't backport the change. executeCommand(…) is no longer called and we don't want to break compatibility in a bugfix release.

The easiest approach for you can be to override the aggregate(…) method and call the appropriate method, DBCollection.aggregate(…) with the mapped aggregation pipeline.

Upgrading the spring boot version didn't work for me. Changing outputmode as cursor as providing a cursor is mandatory, worked. Verified in mongo 3.6

List<DBObject> list = new ArrayList<DBObject>();
list.add(unwind.toDBObject(Aggregation.DEFAULT_CONTEXT));
list.add(group.toDBObject(Aggregation.DEFAULT_CONTEXT));
list.add(sort.toDBObject(Aggregation.DEFAULT_CONTEXT));

DBCollection col = mongoTemplate.getCollection("users");

Cursor cursor = col.aggregate(list, AggregationOptions.builder().allowDiskUse(true).outputMode(OutputMode.CURSOR).build());

List<AggregationResultVO> result = new ArrayList<AggregationResultVO>();

while(cursor.hasNext()) {
     DBObject object = cursor.next();
     result.add(new AggregationResultVO(object.get("aggregationResultId").toString()));
}
Just updating the spring boot version works for me.
This is the version that I have used and worked....
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
    </parent>

I have also faced this type of error when using org.springframework.data version 1.10.3.RELEASE. And then i have changed version to 2.0.5.RELEASE and my problem was solved.

Solved the issue by upgrading spring boot to the '2.1.3.RELEASE' version.

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <!--<version>1.5.10.RELEASE</version>-->
        <relativePath></relativePath>
    </parent>

If you are having this issue and you are using Studio 3T, there is an option in the Options tab, just check it:

enter image description here

Your command no longer works due to a change in mongodb driver change in version 3.6. You need to invoke it from dbCollection.aggregate(...) method instead.

I've tried all above (short of changing the code to using a cursor) to no avail.

In the end, I had to upgrage

'mongo-java-driver'       : '3.6.2'

Then it worked.

  1. Use Spring Boot 2.0.0 or later.
  2. Add AggregationOptions with cursor to your Aggregation:
AggregationOptions aggregationOptions = AggregationOptions.builder()
    .allowDiskUse(true)
    .cursor(new Document())
    .build();
Aggregation aggregation = Aggregation.newAggregation(aggregationOperations)
    .withOptions(aggregationOptions);
  1. Call aggregateStream() (not aggregate()) method of MongoOperations. This method utilizes the cursor responded by MongoDB:
mongoOps.aggregateStream(aggregation, "collection", MyEntity.class)
Related