Sorting Spring Data MongoDB collections using @OrderBy

This is already third post about tuning and enhancing Spring Data MongoDB capabilities. This time I found that I miss one JPA feature – @OrderBy annotation. @OrderBy specifies the ordering of the elements of a collection valued association at the point when the association is retrieved.

In this article I will show how to implement sorting with @OrderBy annotation with Spring Data MongoDB.  

Use case

Just a short example of what is it all about for those who did not use JPA @OrderBy before. We’ve got here two classes and one to many relation:

package pl.maciejwalkowiak.springdata.mongodb.domain;

import org.bson.types.ObjectId;

public class Backpack {
 private ObjectId id;

 private List<Item> items;

public class Item {
 private String name;
 private int price;


Backpack is here a main class and contains list of embedded items. When Backpack is loaded from database its items are loaded in order close to insertion order. What if we want to change that and order items by one of its fields? We need to implement sorting by our own and again we will extend AbstractMongoEventListener.

Sorting details: introducing @OrderBy

In opposite to JPA – sorting in this case sorting cannot be done on database level. We need to take care about it on application side – that can be done in two places:

  • before object is converted into MongoDB data structure – if we want to make sure that objects are sorted properly inside MongoDB collection
  • after object is converted from MongoDB data structure into Java object – if we just want to make sure that inside our application List is sorted properly

In order to specify in which place sorting should take place I have created SortPhase enumeration:

public enum SortPhase {

Finally – @OrderBy annotation will contain three almost self describing properties:

package pl.maciejwalkowiak.springdata.mongodb;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.FIELD })
public @interface OrderBy {
  * Field name
 String value();
 Order order() default Order.ASCENDING;
 SortPhase[] phase() default SortPhase.AFTER_CONVERT;

Implementing SortingMongoEventListener

Declarative sorting has to use reflection. To keep code readable I used commons-beanutils but it could have been done manually without using it. Add following dependencies to your project:



The final part is SortingMongoEventListener implementation:

package pl.maciejwalkowiak.springdata.mongodb;

import com.mongodb.DBObject;
import org.apache.commons.beanutils.BeanComparator;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

 * MongoEventListener that intercepts object before its converted to BasicDBObject (before it is saved into MongoDB)
 * and after its loaded from MongoDB.
 * @author Maciej Walkowiak
public class SortingMongoEventListener extends AbstractMongoEventListener {
 public void onAfterConvert(DBObject dbo, final Object source) {
  ReflectionUtils.doWithFields(source.getClass(), new SortingFieldCallback(source, SortPhase.AFTER_CONVERT));

 public void onBeforeConvert(Object source) {
  ReflectionUtils.doWithFields(source.getClass(), new SortingFieldCallback(source, SortPhase.BEFORE_CONVERT));

  * Performs sorting with field if:
  * <ul>
  * <li>field is an instance of list</li>
  * <li>is annotated with OrderBy annotation</li>
  * <li>OrderBy annotation is set to run in same phase as SortingFieldCallback</li>
  * </ul>
 private static class SortingFieldCallback implements ReflectionUtils.FieldCallback {
  private Object source;
  private SortPhase phase;

  private SortingFieldCallback(Object source, SortPhase phase) {
   this.source = source;
   this.phase = phase;

  public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
   if (field.isAnnotationPresent(OrderBy.class)) {
    OrderBy orderBy = field.getAnnotation(OrderBy.class);

    if (Arrays.asList(orderBy.phase()).contains(phase)) {
     Object fieldValue = field.get(source);

     sort(fieldValue, orderBy);

  private void sort(Object fieldValue, OrderBy orderBy) {
   if (ClassUtils.isAssignable(List.class, fieldValue.getClass())) {
    final List list = (List) fieldValue;

    if (orderBy.order() == Order.ASCENDING) {
     Collections.sort(list, new BeanComparator(orderBy.value()));
    } else {
     Collections.sort(list, new BeanComparator(orderBy.value(), Collections.reverseOrder()));


In order to use it you just need to declare this class as a Spring bean in application context:

<bean class="pl.maciejwalkowiak.springdata.mongodb.SortingMongoEventListener" />


Now its time to add created OrderBy annotation to Backpack class from beginning of this post. Lets say we want to order items by price in descending order:

public class Backpack {
 private ObjectId id;

 @OrderBy(value = "price", order = Order.DESCENDING)
 private List<Item> items;


Thats it. Now every time you load Backpack objects – does not matter if its findAll, findOne or your custom method – items in backpack will be ordered.  


SortingMongoEventListener is another example how Spring Data MongoDB event system is powerful. You are welcome to comment and let me know if you think this feature could be a part of Spring Data MongoDB.

Reference: Sorting Spring Data MongoDB collections using @OrderBy from our JCG partner Maciej Walkowiak at the Software Development Journey blog.

Related Whitepaper:

Open Source Data Management for Big Data and NoSQL

Join Talend for this new on-demand webinar to show how data management can benefit your organization.

This on-demand webinar shows how Talend for Big Data greatly simplifies the process of working with Hadoop and NoSQL and makes Big Data integration easy, fast, and affordable.

Get it Now!  

Leave a Reply

− 1 = seven

Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books
Get tutored by the Geeks! JCG Academy is a fact... Join Now
Hello. Add your message here.