Using dynamic query for spring mvc pagination - java

I am trying to implement pagination in spring mvc.
In my case, I have a Review entity which consists of reviewStatus and the date it was submitted on.
I am trying to use JpaRepository, but I am not sure how to support the following search query using it.
SELECT * from review WHERE review.reviewStatus = 2 AND
( review.submittedOn BETWEEN '2015-09-08' AND '2015-09-09' )
I can see(refer http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html) that we can define methods for particular queries like findbyname.
However, in my case, if the user doesn't provide status then the above query simply becomes:
SELECT * from review WHERE ( review.submittedOn BETWEEN
'2015-09-08' AND '2015-09-09' )
and if there is no submitted date provided, it becomes
SELECT * from review WHERE review.reviewStatus = 2
In short, the query depends upon the values entered by the end-user and I wish to use the same parameters to implement pagination.
Please guide and/or share links to implement same.
Thanks in advance.

Have a look at http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/PagingAndSortingRepository.html
You can pass a Pageable object into the findAll method
http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Pageable.html
As per http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-seven-pagination/
public List<Person> search(String searchTerm, int pageIndex) {
LOGGER.debug("Searching persons with search term: " + searchTerm);
//Passes the specification created by PersonSpecifications class and the page specification to the repository.
Page requestedPage = personRepository.findAll(lastNameIsLike(searchTerm), constructPageSpecification(pageIndex));
return requestedPage.getContent();
}
/**
* Returns a new object which specifies the the wanted result page.
* #param pageIndex The index of the wanted result page
* #return
*/
private Pageable constructPageSpecification(int pageIndex) {
Pageable pageSpecification = new PageRequest(pageIndex, NUMBER_OF_PERSONS_PER_PAGE, sortByLastNameAsc());
return pageSpecification;
}

have a look this for spring mvc paging: How to implement pagination in Spring MVC 3
As for you dynamic query, you may use a Stringbuilder to build your query based on user input. Somewhere along the lines of:
pulic YourDomainObject searchDynamically(String reviewStatus, String date){
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM review WHERE ");
if(null != reviewStatus && null != date){
sql.append(" reviewStatus = ? and date = ? ");
}elseif(null != reviewStatus){
sql.append(" reviewStatus = ? ");
}elseif(null != date){
sql.append(" date = ? ");
}
}

Related

Offset in pagination of cosmosDb not supported in spring data cosmosdb library

I am trying to get data by pagination from CosmosTemplate.paginationQuery(), but the problem is I am not getting data from the offset that I am setting in pagination object. Below is my code for setting pagination,
DocumentQuery documentQuery = new DocumentQuery(criteriaList, CriteriaType.AND));
if (Objects.nonNull(Offset) && Objects.nonNull(limit)) {
PageRequest cosmosPageRequest = CosmosPageRequest.of(Offset, limit);
documentQuery.with(cosmosPageRequest);
Page<User> page = cosmosTemplate.paginationQuery(documentQuery, User.class, COLLECTION_NAME);
...
}
This always returns me list with first set of objects. So for example when I am setting offset as 11 and limit 10, it is always returning me records with offset 0 to 10. I tried to check library as well but there also no where they are setting offset while retrieving records. Below is the code for the same form azure-cosmosdb library AbstractQueryGenerator.generateCosmosQuery().
protected SqlQuerySpec generateCosmosQuery(#NonNull CosmosQuery query,
#NonNull String queryHead) {
final Pair<String, List<Pair<String, Object>>> queryBody = generateQueryBody(query);
String queryString = String.join(" ", queryHead, queryBody.getFirst(), generateQueryTail(query));
final List<Pair<String, Object>> parameters = queryBody.getSecond();
List<SqlParameter> sqlParameters = parameters.stream()
.map(p -> new SqlParameter("#" + p.getFirst(),
toCosmosDbValue(p.getSecond())))
.collect(Collectors.toList());
if (query.getLimit() > 0) {
queryString = new StringBuilder(queryString)
.append("OFFSET 0 LIMIT ")
.append(query.getLimit()).toString();
}
return new SqlQuerySpec(queryString, sqlParameters);
}
Over here also hard coding for offset is done instead of taking from pagination object. Please can anyone suggest if I am doing anything wrong or getting records based on offset is not supported in this library.
This is a bug in the azure-spring-data-cosmos SDK, where it does not honor the OFFSET as part of CosmosPageRequest and always set it to 0.
It is currently being investigated and will be fixed soon. Follow this issue for updates - https://github.com/Azure/azure-sdk-for-java/issues/28032
However, as a workaround for now, the best way would be to use a custom query using query annotation as mentioned in this example - Usage of offset - https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/cosmos/azure-spring-data-cosmos-test/src/test/java/com/azure/spring/data/cosmos/repository/integration/ContactRepositoryIT.java#L235
Query annotation - https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/cosmos/azure-spring-data-cosmos-test/src/test/java/com/azure/spring/data/cosmos/repository/repository/ContactRepository.java#L39

get 400K data from tables in Spring MVC within some sec

I'm using Spring MVC and I need to get more than 400k datas by my table where i also using JOIN in mysql query.
What I actually have is a Controller that returns which contains a List. I call the Controller using AJAX.
The problem with my solution is that I'm not able to get the data of List with in seconds it take more than 5 minutes to load on JSP page.
In page Jquery..
$(document).ready(function ajaxPost() {
$.ajax({
type: "GET",
data: page,
url: "allListAjax",
success: function(list) {
//here i get responce list and page which takes 5 minutes
}//success
}//ajax
}//ready
In Controller..
#RequestMapping(value="/allListAjax")
public #ResponseBody IVRRouteReportWrapper dashoardAjax(Model model, #RequestParam(required = false) Integer page) {
IVRRouteReportWrapper wrappObj= new IVRRouteReportWrapper();
List<IVRRouteReport> list = ivrRouteServiceInterface.getAllIVRRouteReport(page);
wrappObj.setIVRouteReportList(list);
wrappObj.setPage(page);
return wrappObj;
}
here, IVRRouteReportWrapper is a Domain model which contains setters and getters of List and page.
In Service Implementation...
public List<IVRRouteReport> getAllIVRRouteReport(Integer page) {
return ivrRouteDAOInterface.getAllIVRRouteReport(page);
}
In Dao Implementation...
public List<IVRRouteReport> getAllIVRRouteReport(Integer page) {
if(page==null) {
page = 0;
}else {
page = page*200;
}
String strqry= "SELECT c.caller_id_number as caller_id_number, c.destination_number as destination_number,"
+" c.created_time as created_time, vbDtmf.digit as dtmf FROM VoiceBroadcastDTMF vbDtmf "
+"LEFT JOIN cdr c ON vbDtmf.uuid=c.orig_id ORDER BY c.created_time DESC";
Query query = getSession().createSQLQuery(strqry)
.addScalar("caller_id_number", new StringType())
.addScalar("destination_number", new StringType())
.addScalar("created_time", new StringType())
.addScalar("dtmf", new StringType())
.setResultTransformer(Transformers.aliasToBean(IVRRouteReport.class))
.setFirstResult(page)
.setMaxResults(200);
List<IVRRouteReport> ivrRouteReportList =(List<IVRRouteReport>) query.getResultList();
getSession().flush();
return ivrRouteReportList;
}
Is there any way to return this List Fast on jsp page ? Thanks in advance.
Index the "created_time" column and also omit not required fields by specifying only the required fields in the query as below
String strqry= "SELECT c.caller_id_number as caller_id_number, c.destination_number as destination_number,"
+" c.created_time as created_time, vbDtmf.digit as dtmf FROM VoiceBroadcastDTMF vbDtmf "
+"LEFT JOIN (SELECT caller_id_number , destination_number , created_time FROM cdr) as c ON vbDtmf.uuid=c.orig_id ORDER BY c.created_time DESC";
Go for pagination.
Refer spring-mvc-pagination

Flexible search with parameters return null value

I have to do this flexible search query in a service Java class:
select sum({oe:totalPrice})
from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}}
where {or:versionID} is null and {or:orderType} in (8796093066999)
and {or:company} in (8796093710341)
and {or:pointOfSale} in (8796097413125)
and {oe:ecCode} in ('13','14')
and {or:yearSeason} in (8796093066981)
and {os:code} not in ('CANCELED', 'NOT_APPROVED')
When I perform this query in the hybris administration console I correctly obtain:
1164.00000000
In my Java service class I wrote this:
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
BigDecimal aggregatedValue = new BigDecimal(0);
final StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("select sum({oe:").append(total).append("})");
queryBuilder.append(
" from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk} join OrderEntry as oe on {or.pk}={oe.order}}");
queryBuilder.append(" where {or:versionID} is null");
if (queryParameters != null && !queryParameters.isEmpty()) {
appendWhereClausesToBuilder(queryBuilder, queryParameters);
}
queryBuilder.append(" and {os:code} not in ('");
queryBuilder.append(CustomerOrderStatus.CANCELED.getCode()).append("', ");
queryBuilder.append("'").append(CustomerOrderStatus.NOT_APPROVED.getCode()).append("')");
FlexibleSearchQuery query = new FlexibleSearchQuery(queryBuilder.toString(), queryParameters);
List<BigDecimal> result = Lists.newArrayList();
query.setResultClassList(Arrays.asList(BigDecimal.class));
result = getFlexibleSearchService().<BigDecimal> search(query).getResult();
if (!result.isEmpty() && result.get(0) != null) {
aggregatedValue = result.get(0);
}
return aggregatedValue;
}
private void appendWhereClausesToBuilder(StringBuilder builder, Map<String, Object> params) {
if ((params == null) || (params.isEmpty()))
return;
for (String paramName : params.keySet()) {
builder.append(" and ");
if (paramName.equalsIgnoreCase("exitCollection")) {
builder.append("{oe:ecCode}").append(" in (?").append(paramName).append(")");
} else {
builder.append("{or:").append(paramName).append("}").append(" in (?").append(paramName).append(")");
}
}
}
The query string before the search(query).getResult() function is:
query: [select sum({oe:totalPrice}) from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}} where {or:versionID} is null
and {or:orderType} in (?orderType) and {or:company} in (?company)
and {or:pointOfSale} in (?pointOfSale) and {oe:ecCode} in (?exitCollection)
and {or:yearSeason} in (?yearSeason) and {os:code} not in ('CANCELED', 'NOT_APPROVED')],
query parameters: [{orderType=OrderTypeModel (8796093230839),
pointOfSale=B2BUnitModel (8796097413125), company=CompanyModel (8796093710341),
exitCollection=[13, 14], yearSeason=YearSeasonModel (8796093066981)}]
but after the search(query) result is [null].
Why? Where I wrong in the Java code? Thanks.
In addition, if you want to disable restriction in your java code. You can do like this ..
#Autowired
private SearchRestrictionService searchRestrictionService;
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
searchRestrictionService.disableSearchRestrictions();
// You code here
searchRestrictionService.enableSearchRestrictions();
return aggregatedValue;
}
In the above code, You can disabled the search restriction and after the search result, you can again enable it.
OR
You can use sessionService to execute flexible search query in Local View. The method executeInLocalView can be used to execute code within an isolated session.
(SearchResult<? extends ItemModel>) sessionService.executeInLocalView(new SessionExecutionBody()
{
#Override
public Object execute()
{
sessionService.setAttribute(FlexibleSearch.DISABLE_RESTRICTIONS, Boolean.TRUE);
return flexibleSearchService.search(query);
}
});
Here you are setting DISABLE RESTRICTIONS = true which will run the query in admin context [Without Restriction].
Check this
Better i would suggest you to check what restriction exactly applying to your item type. You can simply check in Backoffice/HMC
Backoffice :
Go to System-> Personalization (SearchRestricion)
Search by Restricted Type
Check Filter Query and analysis your item data based on that.
You can also check its Principal (UserGroup) on which restriction applied.
To confirm, just check by disabling active flag.
Query in the code is running not under admin user (most likely).
And in this case the different search Restrictions are applied to the query.
You can see that the original query is changed:
start DB logging (/hac -> Monitoring -> Database -> JDBC logging);
run the query from the code;
stop DB logging and check log file.
More information: https://wiki.hybris.com/display/release5/Restrictions
In /hac console the admin user is usually used and restrictions will not be applied because of this.
As the statement looks ok to me i'm going to go with visibility of the data. Are you able to see all the items as whatever user you are running the query as? In the hac you would be admin obviously.

How can I retrieve DBObjects that contains a substring of a search-word?

I am using MongoDB with Java Driver (http://tinyurl.com/dyjxz8k). In my application I want it to be possible to give results that contains a substring of the users search-term. The method looks like this:
*searchlabel = the name of a field
*searchTerm = the users searchword
private void dbSearch(String searchlabel, String searchTerm){
if(searchTerm != null && (searchTerm.length() > 0)){
DBCollection coll = db.getCollection("MediaCollection");
BasicDBObject query = new BasicDBObject(searchlabel, searchTerm);
DBCursor cursor = coll.find();
cursor = coll.find(query);
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
//view.showResult(cursor.next());
}
} finally {
cursor.close();
}
}
}
Does anybody have any idea about how I can solve this? Thanks in advance =) And a small additional question: How can I handle the DBObjects according to presentation in (a JLabel in) view?
For text-searching in Mongo, there are two options:
$regex operator - however unless you have a simple prefix regexp, queries won't use an index, and will result in a full scan, which usually is slow
In Mongo 2.4, a new text index has been introduced. A text query will split your query into words, and do an or-search for documents including any of the words. Text indexes also eliminate some stop-words and have simple stemming for some languages (see the docs).
If you are looking for a more advanced full-text search engine, with more powerful tokenising, stemming, autocomplete etc., maybe a better fit would be e.g. ElasticSearch.
I use this method in the mongo console to search with a regular expression in JavaScript:
// My name to search for
var searchWord = "alex";
// Construct a query with a simple /^alex$/i regex
var query = {};
query.animalName = new RegExp("^"+searchWord+"$","i");
// Perform find operation
var lionsNamedAlex = db.lions.find(query);

App Engine Java: syntax for setting query limit and start offset.

I have a list of games in GAE datastore and I want to query fixed number of them, starting from a certain offset, i.e. get next 25 games starting form entry with id "75".
PersistenceManager pm = PMF.get().getPersistenceManager(); // from Google examples
Query query = pm.newQuery(Game.class); // objects of class Game are stored in datastore
query.setOrdering("creationDate asc");
/* querying for open games, not created by this player */
query.setFilter("state == Game.STATE_OPEN && serverPlayer.id != :playerId");
String playerId = "my-player-id";
List<Game> games = query.execute(playerId); // if there's lots of games, returned list has more entries, than user needs to see at a time
//...
Now I need to extend that query to fetch only 25 games and only games following entry with id "75". So the user can browse for open games, fetching only 25 of them at a time.
I know there's lots of examples for GAE datastore, but those all are mostly in Python, including sample code for setting limit on the query.
I am looking for a working Java code sample and couldn't find one so far.
It sounds like you want to facilitate paging via Query Cursors. See: http://code.google.com/appengine/docs/java/datastore/queries.html#Query_Cursors
From the Google doc:
public class ListPeopleServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Query q = new Query("Person");
PreparedQuery pq = datastore.prepare(q);
int pageSize = 15;
resp.setContentType("text/html");
resp.getWriter().println("<ul>");
FetchOptions fetchOptions = FetchOptions.Builder.withLimit(pageSize);
String startCursor = req.getParameter("cursor");
// If this servlet is passed a cursor parameter, let's use it
if (startCursor != null) {
fetchOptions.startCursor(Cursor.fromWebSafeString(startCursor));
}
QueryResultList<Entity> results = pq.asQueryResultList(fetchOptions);
for (Entity entity : results) {
resp.getWriter().println("<li>" + entity.getProperty("name") + "</li>");
}
resp.getWriter().println("</ul>");
String cursor = results.getCursor().toWebSafeString();
// Assuming this servlet lives at '/people'
resp.getWriter().println(
"<a href='/people?cursor=" + cursor + "'>Next page</a>");
}
}
Thanks everyone for help. The cursors was the right answer.
The thing is that I am pretty much stuck with JDO and can't use DatastoreService, so I finally found this link:
http://code.google.com/appengine/docs/java/datastore/jdo/queries.html#Query_Cursors

Categories

Resources