J. Akansha
J. Akansha

Reputation: 27

Query a mongo db collection via a Spring Boot Rest API to return results in a paginated format

There is a collection present in Mongo that has a few attributes. This gets saved whenever any transaction happens in the engine. I need an API that enables the users to search the AnaysisJob by one or more combinations of the following attributes: • startedBy • startedAt (we’ll need a “from” and “to” and we’re searching using a between clause). • status.

The users can search using a single attribute or a combination of the above attributes. If a combination is used then it must be “AND”ed.

Not to forget, it must support pagination too.

Below are the classes :

AnalysisJobSearchCriteria.java

@Data
@Document
public class AnalysisJobSearchCriteria {
    private Long startedAt = System.currentTimeMillis();
    private String startedBy;
    private AnalysisJobStatusType status;
}

AnalysisJobResource.java

@Slf4j
@Api(value = "Analysis Job Resource", tags = "CONNECTIONS")
@RestController
@RequestMapping("/api/v1")
public class AnalysisJobResource {

    @Autowired
    private AnalysisJobSearchService analysisJobSearchService;

    @ApiOperation(value = "Analysis", response = Map.class)
    @ApiResponses({
            @ApiResponse(code = 400, message = "Bad Request"),
            @ApiResponse(code = 404, message = "Not found"),
            @ApiResponse(code = 200, message = "OK")
    })
    @PostMapping(value = "/analysis-job", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<?> searchAnalysisJob(@RequestBody final AnalysisJobSearchCriteria analysisJobSearchCriteria) {
        AggregationResults<AnalysisJobResource> analysisJob = analysisJobSearchService.searchAnalysisJobs(analysisJobSearchCriteria);
        return new ResponseEntity<>(analysisJob, HttpStatus.OK);
    }
}

AnalysisJobSearchService.java

@Service
public class AnalysisJobSearchService {

    private final AnalysisJobCustomRepositoryImpl analysisJobCustomRepositoryImpl;

     @Autowired
        public AnalysisJobSearchService(final AnalysisJobCustomRepositoryImpl analysisJobCustomRepositoryImpl) {
            this.analysisJobCustomRepositoryImpl = analysisJobCustomRepositoryImpl;
        }

    public AggregationResults<AnalysisJobResource> searchAnalysisJobs(AnalysisJobSearchCriteria analysisJobSearchCriteria) {
        AggregationResults<AnalysisJobResource> analysisJob = analysisJobCustomRepositoryImpl.searchAnalysisJob(analysisJobSearchCriteria);
        return analysisJob;
    }

}

AnalysisJobCustomRepository.java

@SuppressWarnings("unchecked")
@Override
public AggregationResults<AnalysisJobResource> searchAnalysisJob(AnalysisJobSearchCriteria analysisJobSearchCriteria) {
    MatchOperation salaryMatch = null;
    if (!analysisJobSearchCriteria.getStatus().equals(null)) {
    salaryMatch = Aggregation.match(new Criteria("status").is(analysisJobSearchCriteria.getStatus()));
    }

    Aggregation aggregation = Aggregation.newAggregation(salaryMatch);

    AggregationResults<AnalysisJobResource> result = mongoTemplate.aggregate(
            aggregation, "result", AnalysisJobResource.class);
    return result;
}

These are some of the classes I have. I also have a Connection class to establish connection with my database and the connection works fine. It is just that I am not able to come up with a query along with the mongo template for my scenario to work.

As I am new to using Mongo with Spring Boot, any kind of help would be appreciated. Also, I believe that it would be better if the service returns List rather than AggregationResult. But how to create a query in Java for Mongo has got me all confused.

Upvotes: 0

Views: 1147

Answers (2)

nestdimmy
nestdimmy

Reputation: 71

You can use AggregationOperation for this issue

private List<SearcheableEntity> searchSmth(CustomCriteria criteria){

  List<AggregationOperation> operations = new ArrayList<>();

  //it's simple way, better pattern is to create criteria builder, 
  //witch will create Criteria.class object from request params
  operations.add(Aggregation.match(Criteria.where("name").is(criteria.getName());

  //For pagination skip and limit methods can be used
  operations.add(Aggregation.skip(criteria.getOffset() != null ? criteria.getOffset() : 0));
  operations.add(Aggregation.limit(criteria.getLimit() != null ? criteria.getLimit() : Integer.MAX_VALUE));

  return mongoTemplate
                .aggregate(Aggregation.newAggregation(operations),
                           "Collection_name", 
                           SearcheableEntity.class
                ).getMappedResults();
}

Also if you need to have logical OR or AND on in your search you can create search criteria in such patterns

new Criteria().andOperator(firstCrinteria, ..., lastCriteria)
new Criteria().orOperator(firstCrinteria, ..., lastCriteria)

For your example

SuppressWarnings("unchecked")
@Override
public List<AnalysisJobResource> searchAnalysisJob(AnalysisJobSearchCriteria criteria) {
  List<AggregationOperation> operations = new ArrayList<>();

  if (!criteria.getStatus() != null) {
     operations.add(Aggregation.match(Criteria.where("status").is(criteria.getStatus())));
  }
  if(!criteria.getStartedAt().equals(null)){ 
  operations.add(Aggregation.match(Criteria.where("time").gt(criteria.getStartedAt()));
  }

return mongoTemplate.aggregate(
        Aggregation.newAggregation(operations), "result", AnalysisJobResource.class).getMappedResults();

}

Upvotes: 1

Lungu Daniel
Lungu Daniel

Reputation: 844

For pagination you can use org.springframework.data.domain.Page and org.springframework.data.domain.Pageable from Spring Data as it's described in the below article

https://reflectoring.io/spring-boot-paging/

Also for searching to MongoDB database it's ok to use Criteria, because it allow you to add dynamically AND / OR clause to your query. You could find an article about how to use Criteria with Spring Data and MongoDB below

https://www.baeldung.com/queries-in-spring-data-mongodb

Upvotes: 0

Related Questions