Skip to content
angelozerr edited this page Dec 22, 2012 · 13 revisions

Pagination

When you wish to display in a DataGrid a lot of data, pagination feature can be usefull. To manage pagination you need several informations:

  • on pagination request, the page range [from-to] indexex of the items to display. This information comes from the the client DataGrid.
  • on pagination response, the paginated items and the total of the items.

To help to manage pagination with MongoDB in your application, Mongo JEE provides some usefull Java pagination classes.

PageResult

For pagination response, it provides com.mongodb.jee.PageResult :

package com.mongodb.jee;

import com.mongodb.DBCursor;
import com.mongodb.DBObject;

public class PageResult {

	private final Iterable<DBObject> items;
	private final int fromItemIndex;
	private final int toItemIndex;
	private final int totalItems;

	public PageResult(DBCursor cursor, int fromItemIndex, int toItemIndex) {
		this(cursor.skip(fromItemIndex).limit(toItemIndex - fromItemIndex + 1),
			fromItemIndex, toItemIndex, cursor.count());
	}

	public PageResult(Iterable<DBObject> items, int fromItemIndex,
		int toItemIndex, int totalItems) {
		this.items = items;
		this.fromItemIndex = fromItemIndex;
		this.toItemIndex = toItemIndex;
		this.totalItems = totalItems;
	}

	public Iterable<DBObject> getItems() {
		return items;
	}

	public int getTotalItems() {
		return totalItems;
	}

	public int getFromItemIndex() {
		return fromItemIndex;
	}

	public int getToItemIndex() {
		return toItemIndex;
	}
}

This Pojo holds the paginated items and the range page indexes information. Here a basic sample with PageResult :

	DB db = mongo.getDB("ecommerce");
	DBCollection col = db.getCollection("products");
	DBCursor allProducts = col.find();
	PageResult result= new PageResult(allProducts, 0, 9);
	
	int from = result.getFromItemIndex(); // =0
	int to = result.getToItemIndex(); // =9
	Iterable<DBObject> pageProducts = result.getItems();

The constuctor with DBCursor uses the basic skip and limit strategy to paginate the DBCursor, but if you don't like this strategy you can use the other constructor.

PageRangeRequest

For pagination request, it provides a Range Pojo dojo.store.PageRangeRequest:

package dojo.store;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import dojo.jaxb.PageRangeRequestAdapter;

@XmlJavaTypeAdapter(PageRangeRequestAdapter.class)
public class PageRangeRequest {

	private final int fromIndex;
	private final int toIndex;

	public PageRangeRequest(int fromIndex, int toIndex) {
		this.fromIndex = fromIndex;
		this.toIndex = toIndex;
	}

	public int getFromIndex() {
		return fromIndex;
	}

	public int getToIndex() {
		return toIndex;
	}

	@Override
	public String toString() {
		return new StringBuilder("items=").append(getFromIndex()).append("-")
			.append(getToIndex()).toString();
	}
}

which is a basic Pojo which holds the page range indexes [from-to].

As you can notice, the package is dojo.store, because it follows the same pagination model as [Dojo JsonRest Paging] (http://dojotoolkit.org/reference-guide/1.8/dojo/store/JsonRest.html#id7)

Note that you need NOT to use this class to manage request pagination, but it can be very usefull to use it if you wish to manage pagination with Dojo Grid and JAX-RS. See explained samples in "With PageRangeRequest" section.

Pagination with JAX-RS

Dojo JsonRest Paging

Mongo JEE Pagination with JAX-RS follows the same idea than the Dojo JsonRest Paging.

Before explaining how to manage pagination with JAX-RS, you need understand how to Dojo JsonRest Paging works.

  • on client side the Dojo Grid (JsonRestStore), calls the REST service. The page range is given in the HTTP Header Request with Range name like this :

     Range: items=0-9
    
  • on server side, the REST service must returns :

  • the paginated items as JSON array.

  • the information about page range indexes and total items in a HTTP Header Response with Content-Range like this:

    		Content-Range: items 0-9/1000
    

This idea avoids to polluate request and response with page range indexes information (no need to return a JSON which contains page range and total items information, a JSON array is enough).

Pagination with JAX-RS

The JAX-RS PageResultProvider manages pagination with the same idea than Dojo JsonRestStore. On other words, it works with PageResult and serialize the PageResult#getItems() as JSON array and register in the HTTP Header response the Content-Range with range and total items information.

Without PageRangeRequest

Here a sample :

@GET
@Path("/findPage")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public PageResult findPage(@QueryParam("from") int fromItemIndex,
		@QueryParam("to")) {
	DB db = mongo.getDB("ecommerce");
	DBCollection col = db.getCollection("products");
	return new PageResult(col.find(), fromItemIndex, toItemIndex);
}

In this sample, if you consume the REST service like this /findPage?find=0&to=9

the JAX-RS PageResultProvider will return the paginated JSON array and HTTP Header Response like this:

Content-Range: items 0-9/1000

With PageRangeRequest

If you wish to use Dojo JsonRestStore, your service must get the Range parameter of the HTTP Request. You could use JAX-RS @HeaderParam and set a String range in your service and parse the Sting (items=0-9) to get range from and to :

...	
public PageResult findPage(@HeaderParam("Range") String range) {
	// search from (0) in the range (items=0-9) 
	int from = ...
	// search to (9) in the range (items=0-9) 
	int to = ...
	...
}

Mongo JEE provides PageRangeRequestAdapter which is a JAXB XmlAdapter which do that. So you can write your service like this:

public PageResult findPage(@HeaderParam("Range") PageRangeRequest range) {
	...
}

Here a sample REST service which can be used with the Dojo JsonRest Paging (ex:Dojo Grid):

@GET
@Path("/findPage")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public PageResult findPage(@HeaderParam("Range") PageRangeRequest range) {
	DB db = mongo.getDB("ecommerce");
	DBCollection col = db.getCollection("products");
	return new PageResult(col.find(), range.getFromIndex(), range.getToIndex());
}