Skip to content

Aggregations should be able to handle Sort.unsorted() #4703

Open
@bithazard

Description

@bithazard

Hi. When you create an aggregation pipeline and use a sort operation with Sort.unsorted() an exception is thrown (UncategorizedMongoDbException). The reason for the exception is, that the sort stage is created but it is simply an empty object. You can reproduce the behavior with the following example:

import org.bson.Document;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.sort;

/* Example documents in database "test", collection "test" (not strictly required to reproduce the exception):
      {
          "_id" : ObjectId("51a4da9b292904caffcff6eb"),
          "x" : 0
      }

      {
          "_id" : ObjectId("51a4da9b292904caffcff6ec"),
          "x" : 1
      }

      {
          "_id" : ObjectId("51a4da9b292904caffcff6ed"),
          "x" : 2
      }
 */
@SpringBootApplication
public class MongodbSortSscce implements CommandLineRunner {
    private final MongoTemplate mongoTemplate;

    public MongodbSortSscce(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public static void main(String[] args) {
        SpringApplication.run(MongodbSortSscce.class, args);
    }

    @Override
    public void run(String... args) {
        //results in: {"find": "test", "filter": {}}
        mongoTemplate.find(new Query().with(Sort.unsorted()), Document.class, "test");             //works

        //results in: {"aggregate": "test", "pipeline": [{"$sort": {"x": 1}}]}
        mongoTemplate.aggregate(newAggregation(sort(Sort.by("x"))), "test", Document.class);       //works

        //results in: {"aggregate": "test", "pipeline": [{"$sort": {}}]}
        mongoTemplate.aggregate(newAggregation(sort(Sort.unsorted())), "test", Document.class);    //fails with "$sort stage must have at least one sort key"
    }
}

You can see that it works when you sort by an arbitrary field (x in the example above). It also works when using find instead of aggregate. In this case the sort operation never reaches the MongoDB(-driver) but is removed somewhere in between. This should also happen for an aggregation in my opinion.

Of course a developer can make sure that an unsorted sort operation is never added to the pipeline (in a real world scenario the sort field will probably come from a URL parameter or something like that - so it's not as obvious as in the example) but that implies that the developer is aware that an exception will be thrown otherwise.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions