Too much of anything can be a bad thing. That's not only true with chocolate, it's also true with results returned from MongoDB aggregation pipelines.

Fortunately, you can limit the results you get back so you don't return all documents. And you can do it right there in your Spring Boot application with the aid of MongoTemplate.

I'll show you how to make that happen in this article.

Alternatively, you can just go grab the source code and work from there.

The Business Requirements

Your boss Smithers walks into your office wearing a baseball cap.

"About that CRM app you're working on," he says as he sits down. "I need you to make an update to one of your service requests.'

You have no idea why he's wearing the baseball cap.

"The request that retrieves all contacts based on their source works well, but some users might want to limit the number of results returned," Smithers says. "Add a limit to that request."

He walks out of your office but you still have no idea why he's wearing a baseball cap.

Familiar Territory

As Smithers mentioned, you've already created a service request that filters contacts based on their source. But it returns all contacts that match the criteria.

Now, you need to allow users to specify a maximum number of results returned.

Fortunately, you can do that a simple addition to your existing code. That's because the code uses a MongoDB aggregation pipeline. All you need to do is add another stage to that pipeline.

For the purposes of this guide, I'll assume you know how to set up MongoTemplate in Spring Boot. I'll also assume you know the basics of MongoDB aggregations.

If you need a refresher on either of those topics, feel free to check out the previous guide on that subject. Then come back here.

The Service, Revisited

Here's what your service looks like right now:

@Service
public class ContactService {

    private static final Logger LOG = LoggerFactory.getLogger(ContactService.class);
	
    
	@Autowired
	private MongoTemplate mongoTemplate;
	
	
	public List<Contact> findContactsBySource(Source source) {
		AggregationOperation match = Aggregation.match(Criteria.where("source").is(source));
		AggregationOperation sort = Aggregation.sort(Direction.ASC, "lastName"); 
		
		Aggregation aggregation = Aggregation.newAggregation(match, sort);
		
		List<Contact> contacts = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Contact.class), Contact.class).getMappedResults();
		
		return contacts;
	}
}

That code handles the process of finding all contacts who match the specified source criteria. Then it returns those contacts sorted alphabetically by last name.

You can test that method out with the following initialization code:

@Component
public class ApplicationListenerInitialize implements ApplicationListener<ApplicationReadyEvent>  {
	
	@Autowired
	private ContactService contactService;
	
    public void onApplicationEvent(ApplicationReadyEvent event) {
    	List<Contact> contacts = contactService.findContactsBySource(Source.EMAIL);
    	
    	try {
	    	ObjectMapper objectMapper = new ObjectMapper();
	    	objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
	    	objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
	    	System.err.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(contacts));
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }
}

Start up your Spring Boot application and when the dust settles you should see an output of all contacts with the source field set to "EMAIL." It will look something like this:

[ {
  "id" : "5fde1ac084dad94dbb7f82ae",
  "firstName" : "R2D2",
  "lastName" : "Droid",
  "email" : "r2d2@xmail.com",
  "source" : "EMAIL",
  "status" : "ACTIVE",
  "statusChange" : 0,
  "linesOfBusiness" : [ "JAVA_ENTERPRISE" ],
  "company" : "For Luke",
  "title" : "Droid",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
}, {
  "id" : "5fdd0cedaac5f75d62564ee7",
  "firstName" : "Jabba",
  "lastName" : "Hutt",
  "email" : "jabba@xmail.com",
  "source" : "EMAIL",
  "status" : "NEW",
  "statusChange" : 0,
  "linesOfBusiness" : [ "ANGULAR" ],
  "company" : "Sandz",
  "title" : "Large",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
}, {
  "id" : "5fd5f37bde602d3bacef69db",
  "firstName" : "Luke",
  "lastName" : "Skywalker",
  "email" : "luke@tat2.com",
  "source" : "EMAIL",
  "sourceDetails" : "He emailed me",
  "status" : "NEW",
  "statusChange" : 0,
  "linesOfBusiness" : [ "ANGULAR" ],
  "company" : "International Business",
  "title" : "President",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
}, {
  "id" : "5fdd0f2aea599836ca3ddbf1",
  "firstName" : "Han",
  "lastName" : "Solo",
  "email" : "han@xmail.com",
  "addresses" : [ {
    "street1" : "111 Millennium Way",
    "city" : "Nessy",
    "state" : "CO",
    "addressType" : "HOME"
  } ],
  "source" : "EMAIL",
  "status" : "ACTIVE",
  "statusChange" : 0,
  "title" : "Pirate",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
} ]

But that's all contacts that match the criteria. Now you need to limit the number returned.

Take It to the Limit

Update the ContactService code to look like this:

@Service
public class ContactService {

    private static final Logger LOG = LoggerFactory.getLogger(ContactService.class);
	
    
	@Autowired
	private MongoTemplate mongoTemplate;
	
	
	public List<Contact> findContactsBySource(Source source, long maxDocuments) {
		AggregationOperation match = Aggregation.match(Criteria.where("source").is(source));
		AggregationOperation sort = Aggregation.sort(Direction.ASC, "lastName"); 
		AggregationOperation limit = Aggregation.limit(maxDocuments);
		
		Aggregation aggregation = Aggregation.newAggregation(match, sort, limit);
		
		List<Contact> contacts = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Contact.class), Contact.class).getMappedResults();
		
		return contacts;
	}
}

The findContactsBySource() method now accepts a maxDocuments parameter. Unsurprisingly, that parameter specifies the maximum number of documents to return.

Also, pay attention to the third AggregationOperation in the list above. That limits the number of documents to return based on the value of the parameter.

And, of course, the code also includes that new operation in the newAggregation() method.

Everything else stays the same.

However, you now have a compilation error in your initialization code. Update it to return only two documents like this:

List<Contact> contacts = contactService.findContactsBySource(Source.EMAIL, 2);

Save the file and relaunch the Spring Boot app. Now the output at the beginning should only contain two documents, like this:

[ {
  "id" : "5fde1ac084dad94dbb7f82ae",
  "firstName" : "R2D2",
  "lastName" : "Droid",
  "email" : "r2d2@xmail.com",
  "source" : "EMAIL",
  "status" : "ACTIVE",
  "statusChange" : 0,
  "linesOfBusiness" : [ "JAVA_ENTERPRISE" ],
  "company" : "For Luke",
  "title" : "Droid",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
}, {
  "id" : "5fdd0cedaac5f75d62564ee7",
  "firstName" : "Jabba",
  "lastName" : "Hutt",
  "email" : "jabba@xmail.com",
  "source" : "EMAIL",
  "status" : "NEW",
  "statusChange" : 0,
  "linesOfBusiness" : [ "ANGULAR" ],
  "company" : "Sandz",
  "title" : "Large",
  "authority" : false,
  "salesOwner" : {
    "id" : "5f78d8fbc1d3246ab4303f2b",
    "firstName" : "Darth",
    "lastName" : "Vader",
    "email" : "darth@xmail.com",
    "username" : "darth",
    "phoneNumber" : "474-555-1212"
  }
} ]

As you can see above, the new aggregation operation limits the number of documents returned to two.

So the test is a success.

Wrapping It Up

Now it's over to you. Fiddle around with the code you see above to make some changes.

Even better: combine what you learned here with the skip aggregation operation to create a pagination solution.

Also, feel free to grab the source from GitHub.

Have fun!

Photo by Brett Sayles from Pexels