How to query with Pageable with Spring Data and Couchbase - spring-data

I just try to query with a PageRequest:
Page<MyEntity> entityPage = myRepository.findAll(new PageRequest(1, 20));
and this is my Repository
#Repository
public interface MyRepository extends CouchbasePagingAndSortingRepository<MyEntity, String> {
}
But always get an empty Page object back.
I'm using 2.1.5.RELEASE for spring-data-couchbase. I read in this older question that it wasn't implemented yet - but this was 2015 and in the Spring Data for Couchbase documentation it's described in detail. So I guess it should work by now ...

You are requesting for second page. Pages are zero indexed, thus providing 0 for page will return the first page.
Try this:
Page<MyEntity> entityPage = myRepository.findAll(new PageRequest(0, 20));

Related

Mongo Spring JPA giving IndexOutOfBoundsException in findAll() call

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
at java.util.ArrayList.get(ArrayList.java:433)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.bulkReadAndConvertDBRefMapIntoTarget(MappingMongoConverter.java:1447)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readMap(MappingMongoConverter.java:1047)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:225)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1408)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1355)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:952)
at org.springframework.data.mongodb.core.convert.DefaultDbRefResolverCallback.resolve(DefaultDbRefResolverCallback.java:61)
at org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.resolveDbRef(DefaultDbRefResolver.java:103)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readAssociation(MappingMongoConverter.java:358)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:319)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:292)
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(M
---------------
This is the calling of mongo jpa method
List<LegalDocument> legalDocumentList = legalDocumentRepository.findAll(Pageable.unpaged()).getContent();
-------------------------------------------------------------
This code is showing the Repository
#Repository
public interface LegalDocumentRepository extends MongoRepository<LegalDocument, String> {
#Override
Page<LegalDocument> findAll(Pageable pageable);
}
I was using this findAll() method from a very long. But now it is giving the IndexOutOfBound. Even i have so many methods available into repository. Please help me in fixing this.
Springboot 2.0.5 release and Mongo 4.2 Atlas
MongoRepository extends PagingAndSortingRepository and you don't need to write method in the repository remove it. Just call like this
Page<LegalDocument> legalDocuments = legalDocumentRepository.findAll(Pageable.unpaged());
And you are using Pageable.unpaged() that means you don't need pagination and use getContent() to get list. But you don't need do that, you can directly get list this way.
List<LegalDocument> legalDocumentList = legalDocumentRepository.findAll();

How to find top N elements in Spring Data Jpa?

In Spring Data Jpa to get first 10 rows I can do this findTop10By...(). In my case the number or rows is not defined and comes as a parameter.
Is there something like findTopNBy...(int countOfRowsToGet)?
Here is another way without native query. I added Pageable as a parameter to the method in the interface.
findAllBySomeField(..., Pageable pageable)
I call it like this:
findAllBySomeField(..., PageRequest.of(0, limit)) // get first N rows
findAllBySomeField(..., Pageable.unpaged()) // get all rows
I don't know of a way to do exactly what you want, but if you are open to using #Query in your JPA repository class, then a prepared statement is one alternative:
#Query("SELECT * FROM Entity e ORDER BY e.id LIMIT :limit", nativeQuery=true)
Entity getEntitiesByLimit(#Param("limit") int limit);
Did it by using pagination, as described in the first answer. Just adding a more explicit example.
This example will give you the first 50 records ordered by id.
Repository:
#Repository
public interface MyRepository extends JpaRepository<MyEntity, String> {
Page<MyEntity> findAll(Pageable pageable);
}
Service:
#Service
public class MyDataService {
#Autowired
MyRepository myRepository;
private static final int LIMIT = 50;
public Optional<List<MyEntity>> getAllLimited() {
Page<MyEntity> page = myRepository.findAll(PageRequest.of(0, LIMIT, Sort.by(Sort.Order.asc("id"))));
return Optional.of(page.getContent());
}
}
Found the original idea here:
https://itqna.net/questions/16074/spring-data-jpa-does-not-recognize-sql-limit-command
(which will also link to another SO question btw)

Retrieving additional non DB information using Spring Data Rest

I am using Spring Data Rest to expose a news feed REST API. I want to add an image (location) to the entity which will be retrieved by a separate web service API call.
What is the best way to do this using Spring Data Rest or would I have to create another separate REST API call/domain object etc.?
Any sample code would be fantastic.
You should use a ResourceProcessor
The Spring Data REST exporter executes any discovered ResourceProcessor's before it creates the output representation
#Bean
public ResourceProcessor<Resource<MyEntity>> myEntityProcessor() {
return new ResourceProcessor<Resource<MyEntity>>() {
#Override
public Resource<MyEntity> process(Resource<MyEntity> resource) {
resource.add(new Link("http://localhost:8080/images/images.jpg", "image"));
return resource;
}
};
}
Another example with access to the repository and EntityLinks object that helps to build links related to the entity..
#Component
class MyEntityResourceProcessor implements ResourceProcessor<Resource<MyEntity>> {
#Autoware
private MyEntityRepo repo;
#Autoware
private EntityLinks entityLinks;
#Override
public Resource<MyEntity> process(Resource<MyEntity> resource) {
MyEntity entity = resource.getContent();
// Some entity processing...
Link link entityLinks.linkForSingleResource(entity).slash("...").withRel("...")
resource.add(link);
return resource;
}
}
More examples of using ResourceProcessor you can find in RESTBucks project

oData's skip() and top() pulling entire record set before filtering

i have an oData enabled web api function
[EnableQuery()]
public IQueryable<StoreCommand> Get()
{
return _storeCommandService.GetAllStoreCommands().AsQueryable();
}
the service layer calling Mongodb based Repository pattern's implementation.
public IEnumerable<StoreCommand> GetAllStoreCommands()
{
return _uow.StoreCommands.GetAll();
}
where GetAll is implemented in Repository layer like
public IList<TEntity> GetAll()
{
return _collection.FindAllAs<TEntity>().ToList();
}
where _collection is a MongoCollection of c# driver.
when i make a call like
http://localhost:xxxx/api/storeCommandsrest?$skip=0&$top=10&$orderby=Name
i get top 10 records but it pulls all the records from the DB and send me back top 10.
Please guide how we can pull only the required set from the DB.
Comment moved to answer:
You aren't returning an IQueryable from GetAllStoreCommands(). Your return type must be an IQueryable(). To get that from the driver, it should be _collection.AsQueryable().

Spring data mongo pagination

I want to implement pagination with Spring Data Mongo. There are many tutorials and docs suggest to use PagingAndSortingRepository, like this:
StoryRepo extends PagingAndSortingRepository<Story, String>{}
And so because PagingAndSortingRepository provides api for query with paging, I can use it like:
Page<Story> story = storyRepo.findAll(pageable);
My question is where actually is this findAll method here implemented? Do I need to write its implementation by myself?
The StoryRepoImpl which implements StoryRepo needs to implement this method?
You do not need to implement the method as when you autowired the Spring object PagingAndSortingRepository, it automatically implements the method for you.
Please note that since you are using Mongodb, you can extend MongoRepository instead.
Then in Spring, enable pagination using this:
#RequestMapping(value="INSERT YOUR LINK", method=RequestMethod.GET)
public List<Profile> getAll(int page) {
Pageable pageable = new PageRequest(page, 5); //get 5 profiles on a page
Page<Profile> page = repo.findAll(pageable);
return Lists.newArrayList(page);
I got it working by writing my own implementations, something like this:
List<Story> stories = null;
Query query = new Query();
query.with(pageable);
stories = getTemplate().find(query, Story.class);
long total = getTemplate().count(query, Story.class);
Page<Story> storyPage = new PageImpl<Story>(stories, pageable, total);
return storyPage;
I'm working with spring data & mongodb, using mongo template to query data.
In Spring Data, you create an interface and add a method using the naming conventions used by Spring data and the framework will generate the implementation of that method.
To implement pagination, i create this method declaration in my repository:
public interface PersonRepository extends MongoRepository<Person, ObjectId> {
Page<Person> findByName(String name, Pageable pageable);
}
Then, in my service i call this method like this:
Page<Person> persons = personRepository.findByName("Alex", PageRequest.of(0, 100));
Here, the page will contain 100 element.
To paginate a query, you can use something like below:
public interface PersonRepository extends MongoRepository<Person, String> {
Page<Person> findByFirstname(String firstname, Pageable pageable);
}
For more details, please refer to the second query in Example 6.6 in https://docs.spring.io/spring-data/mongodb/docs/1.2.0.RELEASE/reference/html/mongo.repositories.html
The method is implemented by a store-specific class. For the Spring Data JPA module, it's SimpleJpaRepository. You usually let a DI container create instances for these repository interfaces. With Spring you'd activate Spring Data repositories by either using #EnableJpaRepository on a JavaConfig class or
<jpa:repositories base-package="com.acme.repositories" />
This will create a proxy instance for the repo, so that you can get it injected into your clients:
class MyClient {
#Inject
public MyClient(PersonRepository repository) {
…
}
}
Query query1 = new Query();
Integer startIndex = page * size;
Integer endIndex = (page * size) + size;
List<dto> totalRecord = mongoOperation.find(query1, dto.class);
query1.limit((endIndex > totalRecord.size() ? totalRecord.size() : endIndex));
List<dto> responseList = mongoOperation.find(query1, dto.class);
int end = (endIndex > (totalRecord.size() - 1) ? totalRecord.size() - 1 : endIndex);
if (totalRecord.size() > 0 && end == 0)
end = 1;
if (totalRecord.size() > 0)
responseList = responseList.subList(startIndex, end);
int totalPages = totalRecord.size() / size + (totalRecord.size() % size == 0 ? 0 : 1);
As other answer says: you don't need to implement the repository interface classes. The generating magic will handle it.
I wrote this answer because of say implementation way of PageRequest deprecated
-the Pageable pageable = new PageRequest(fromIndex, toIndex); one.
If you want to implement a pageable request nowadays, you need to use like following:
PageRequest page = PageRequest.of(pageNum, pageSize);
List<MyEntity> result =myEntityRepository.findAll(page).toList();