I'm writing spring boot application. I have the HashTree structure, sorted by specific field. And I have a specific method that iterates through the tree, so if it finds a value (used as comparator) it returns it and does not check for other values.
With code it will look something like this:
class Storage {
TreeSet<Book> tree = new TreeSet<>(Comparator.comparingInt(Book::getNumberOfPages));
public Book getBookWithSmallestNumberOfPagesButGreaterThanSpecific(int number) {
iterator = tree.iterator();
while (iterator.hasNext()) {
Book book = iterator.next();
if (book.getNumberOfPages() > number) {
return book;
}
}
return null;
}
}
Please don't jurge that code, it's just for example, real code is much more complicated.
So I want to do the same thing using Spring JPA, and store Books in database.
My plan is:
create index on numberOfPages column in order to iterate it in asc order
get a coursor to the first database record
return current element or get next element in a cursor.
The thing is I dont know how to get a cursor, all JPA methods return all elements in a List<>.
Please challenge my solution. I don't know if I move in a right direction. I'm pretty new to JPA.
You can use Pageable,
Pageable pageable = PageRequest.of(page, size, direction, property);
List<ENTITY> findByProjectId(String projectId, Pageable pageable);
Related
I need to create a mongotemplate database query to get a specific number of elements into a list.
At the moment I just get all the elements with findAll(), and then I modify the obtained data using code that I have writen within the service class.
Initially, I have a Laptop class with fields price::BigDecimal and name::String and I use findAll() to get a list of them.
Then I put those in a HashMap, where key is the name field, sorted from most expensive to cheapest.
Map<String, List<Laptop>> laptopsMap = laptopsFrom.stream()
.collect(Collectors.groupingBy(Laptop::getName,
Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream()
.sorted(Comparator.comparing(Laptop::getPrice).reversed())
.collect(Collectors.toList())
))
);
So the results are like below:
[{"MSI", [2200, 1100, 900]},
{"HP", [3200, 900, 800]},
{"Dell", [2500, 2000, 700]}]
Then, I use the code in the bottom of the question, to create a Laptop list with the following contents:
[{"HP", 3200}, {"Dell", 2500}, {"MSI", 2200},
{"Dell", 2000}, {"MSI", 1100}, {"HP", 900},
{"MSI", 900}, {"HP", 800}, {"Dell", 700}]
So basically, I iterate the map and from each key, I extract the next in line element of the list.
do {
for (Map.Entry<String, List<Laptop>> entry :
laptopsMap.entrySet()) {
String key = entry.getKey();
List<Laptop> value = entry.getValue();
finalResultsList.add(value.get(0));
value.remove(0);
if (value.size() == 0) {
laptopsMap.entrySet()
.removeIf(pr -> pr.getKey().equals(key));
} else {
laptopsMap.replace(key, value);
}
}
} while(!laptopsMap.isEmpty());
I instead of all this in-class code need to use a mongoTemplate database argument, but I cant seem to figure out how to create such a complex query. I have read material about Aggregation but I have not found anything helpful enough. At the moment, I have started putting a query together as shown below:
Query query = new Query();
query.limit(numOfLaptops);
query.addCriteria(Criteria.where(Laptop.PRICE).gte(minPrice));
I am facing a problem with sorting from Pageable with geo-spatial method in MongoRepository
With the following code I am able to retrieve first requestVo.per_page records when requestVo.page is 0. However the list is not sorted by title.
Another thing I have noticed is that the same PageRequest object is able to give me the sorted pageable list with photoRepository.findAll. Any help is appreciated!
LinkedList<Photo> photos= new LinkedList<Photo>();
PageRequest request = new PageRequest(requestVo.page, requestVo.per_page,Direction.ASC,"title");
for (GeoResult<Photo> photoResult : photoRepository.findByLocationNear(point, distance,request).getContent()) {
photos.add(photoResult.getContent());
}
return photos;
Turns out that GeoResult is blocking the sorting. Working perfect when I just return collection of Photo.
LinkedList<Photo> photos= new LinkedList<Photo>();
PageRequest request = new PageRequest(requestVo.page, requestVo.per_page,Direction.ASC,"title");
for (Photo photoResult : photoRepository.findByLocationNear(point, distance,request)) {
photos.add(photoResult);
}
return photos;
I have a Person index in my ElasticSearch database i get all the persons via this method:
public List<Person> findAll() {
SearchResult result = null;
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(PERSON_INDEX_NAME)
.addType(PERSON_TYPE_NAME).build();
try {
result = client.execute(search);
} catch (IOException e) {
}
List<SearchResult.Hit<Person, Void>> hits = result.getHits(Person.class);
return hits.stream().map(this::getPerson).collect(Collectors.toList());
}
but i want to get the results sorted alphabetically by name (person has String id and String name) but i cant figure out how.
any help is apreciated
What type is your name field?
The problem may be that ElasticSearch is splitting the name up into words, and then it can sort on any word. Which can give some pretty random looking results (e.g. the name "Zachary A. Zincstein" would come out highly, because it contains an "A").
A solution is to have a 2nd field, where you set type keyword in the mapping, and sort on that.
well.
i took the list given by ES and ordered it using the Collections sort method
I am trying to implement pagination feature in Spring Data JPA.
I am referring this Blog
My Controller contains following code :
#RequestMapping(value="/organizationData", method = RequestMethod.GET)
public String list(Pageable pageable, Model model){
Page<Organization> members = this.OrganizationRepository.findAll(pageable);
model.addAttribute("members", members.getContent());
float nrOfPages = members.getTotalPages();
model.addAttribute("maxPages", nrOfPages);
return "members/list";
}
My DAO is following :
#Query(value="select m from Member m", countQuery="select count(m) from Member m")
Page<Organization> findMembers(Pageable pageable);
I am able to show first 20 records, how do I show next 20???
Is there any other pagination example that I can refer??
The constructors of Pageable are deprecated, use of() instead:
Pageable pageable = PageRequest.of(0, 20);
I've seen similar problem last week, but can't find it so I'll answer directly.
Your problem is that you specify the parameters too late. Pageable works the following way: you create Pageable object with certain properties. You can at least specify:
Page size,
Page number,
Sorting.
So let's assume that we have:
PageRequest p = new PageRequest(2, 20);
the above passed to the query will filter the results so only results from 21th to 40th will be returned.
You don't apply Pageable on result. You pass it with the query.
Edit:
Constructors of PageRequest are deprecated. Use Pageable pageable = PageRequest.of(2, 20);
Pageable object by default comes with size 20, page 0, and unsorted
So if you want the next page in front end the url can be sent with query params page, size,sort and these u can test it on postman.
You can use Page, List or Slice.
If you dont need the number of pages, and only need to know if the next page exists, use Slice, since it does not do the "count" query:
for (int i = 0; ; i++) {
Slice<Organization> pageOrganization = organizationRepository.find(PageRequest.of(0, 100));
List<Organization> organizationList = pageOrganization.getContent();
for (Organization org : organizationList) {
// code
}
if (!pageOrganization.hasNext()) {
break;
}
}
I've created a Repository that extends CrudRepository,
this repository has a method with an #Query notation:
Code:
#Query("select itemType, count(*) as count from Item where User_id = :userId group by itemType")
List<Map<String, Long>> countItemsForUser(#Param("userId") Long userId);
The issue I'm having is that this return a ArrayList of Object(s) and not a List of Map.
I've read somewhere that JPA can't return a Map so that's why I stuff the result in a List>.
I don't know what's the best way to work around this issue or to quickly access the result data.
I've tried casting but that didn't work out either:
for(Object item: items) {
Map<String,Long> castedItem = (HashMap<String,Long>)item;
}
See this example in official documentation of Hibernate.Here
for (Object item:items) {
Object[] tuple = (Object[]) item;
String itemType = (String)tuple[0];
Long count = (Long) tuple[1];
}
Most simple way is to use interface. To let Spring wire query alias
to the interface getter. Example can be found here: https://www.baeldung.com/jpa-queries-custom-result-with-aggregation-functions
also there is #SqlResultSetMapping. See:
JPA- Joining two tables in non-entity class