QueryDsl Spring Data Mongodb projecting SpringDataMongodbQuery - mongodb

I wanted to know if there was a way to use QueryDsl's TypeSafe approach to perform a projection on a query in conjunction with Spring Data.
Like for example :
public interface ColorCollectionRepository extends MongoRepository<ColorCollection, String>, QuerydslPredicateExecutor<ColorCollection> {
Optional<ColorCollection> findByCodeIs(String code);
List<ColorCollection> findAll(Predicate predicate);
}
And running a query where I would like to exclude a field named "references"
QColorCollection qColorCollection = QColorCollection.colorCollection;
qColorCollection.code.eq("code");
qColorCollection.exclude("references");
Thanks

Querydsl doesn't support projections for mongodb as of now. You need to implement custom solution for it to work.
I have developed a custom solution which is useful if you want to include specific fields. You may check it here - https://stackoverflow.com/a/66152979/8949877

Related

Spring JPA findBy accent

I am developing a spring-data-jpa application.
I 've ridden the repository with findBy but does not work when I look content with an accent. Does anyone know why?
I am using the following:
Page<Dades> findByNomcomercialIgnoreCaseContaining (#Param ("nomcom") String nomcom, Pageable pageable);
The database is Oracle.
Thanks for your interest.
It's because ignoreCase does not deal with accents. It only compares both String after uppercasing them. See the documentation for more informations.
I don't know any simple solution to ignore accents with Spring Jpa. You coud either :
Remove this parameter in your query, and filter the result in Java afterward (comparing Strings after doing org.apache.commons.lang3.StringUtils.stripAccents).
Use Spring Jpa Specifications. Again, it provides only functionslike upper, like, ... so you have to write your own, depending on what database you are using.
#Param is not required. if you have any query i.e if you are using #Query then we need use #param to pass the specific value releated to query.Below you can check how to use #Query and #Param
#Query("SELECT t.title FROM Todo t where t.id = :id")
String findTitleById(#Param("id") Long id);
if you are not added these annotation use in your repository layer
#Transactional
#Repository
Check another thing i.e
#Transactional
#Repository
public interface IXyzRepository extends CrudRepository<ABC,Integer>{
//some methods you have
}
whether the primary id of class ABC is of type Integer

Writing custom n1ql queries in spring

I'm trying to query a spring-data couchbase repository using N1QL queries. I have two doubts:
I'm using #Query annotation to generate queries, my code looks like this:
#Query("#{#n1ql.selectEntity} WHERE $0 = $1 AND #{#n1ql.filter}")
public Page<GsJsonStore> matchJson(String term, String value, Pageable pageable);
//Query
Page<GsJsonStore> p = repo.matchJson("_object.details.status", "ready", pg);
This query doesn't return any results. However, when I run the same query (below) in cbq I get the desired result:
select * from default where _object.details.status = 'ready';
How can I view the query string generated by the Couchbase repository? I'm using spring-boot. Am I correct in using the #Query annotation for this use-case?
Also, how can I perform n1QL queries on CouchbaseOperations template? I know that there's a findByN1QL method, but I didn't find any good documentation about it. Could someone please explain how to use this?
The query looks ok. You did persist your GsJsonStore entities using the Spring Data Couchbase repository did you?
In order to log all the queries generated and executed by the framework (including inline queries like in your case), you can configure the logger like so in a logback.xml configuration:
<logger name="org.springframework.data.couchbase.repository.query" level="debug"/>
You'll see that the query that got executed and the query that you ran in cbq are not the same, since at least you didn't use a WHERE clause.
In CouchbaseOperations there are two methods relative to N1QL queries:
findByN1QL: this expects specific structure of the query, in order to make sure all data necessary to correct deserialization of a Spring Data annotated entity is selected (which is the purpose of the #n1ql.selectEntity and #n1ql.filter SpEL).
findByN1QLProjection is more free-form. If Jackson can deserialize the results of the provided query to the requested Class, then it will. As such, the SELECT clause is much less implicitly restricted in this method.
To use both, you must pass in a N1qlQuery object from the SDK. Such queries can be constructed using factory methods of the N1qlQuery class, for example:
//a version of the query that is constructed from positional parameters
N1qlQuery queryWithParameter = N1qlQuery.parameterized("SELECT name FROM `beer-sample` WHERE name LIKE $0", JsonArray.from("%dog%"));
//let Spring Data execute the query, projecting to the String class
List<String> beerNamesContainingDog = template.findByN1QLProjection(queryWithParameter, String.class);

Spring LDAP JPA - Limit number of result

I'm using spring-ldap 2.0.4 and spring-data-jpa 1.9.0.
I built a JPA repository like this :
public interface PersonRepo extends LdapRepository<Person> {
Person findByUid (String uid);
#Query("(&(attribute=*{0}*)(attribute2=X)(attribute3=Y))")
List<Person> findByAttributeContains(String attribute);
}
So far everything is fine. I could write methods that fill my needs thanks to query methods.
For some queries i had to use #Query annotation because they were many and operator.
But i would like to limit the number of result to return from my second query method.
I know there is there is the Top and First keywords to define query methods in spring JPA. But I didn't manage to get it work. Plus I want to use multiple and operator in the method.
Thanks
I managed to limit the number of result using XML LDAP configuration.
<ldap:ldap-template context-source-ref="contextSource" count-limit="100"/>

Is it possible to use SpringData MongoDB repository to execute an arbitrary query, with pagination?

We have a use case where a user can pass in arbitrary search criteria for a collection, and wants the output paged. Using Spring Data repositories, this is quite simple if we know ahead of time what attributes they may be searching on by simple extending MongoRepository, and declaring a:
Page<Thing> findByFooAndBarAndBaz(Type foo, Type bar, Type baz, Pageable page)
However, if we generate the query ourselves either using the fluent interface or constructing a mongo string and wrapping it in a BasicQuery class, I can not find a way to get that into a repository instance. There is no:
Page<Thing> findByQuery(Query q, Pageable page)
functionality that I have been able to see.
Nor can I see how to hook into the MongoTemplate querying functionality with the Page abstraction.
I'm hoping I don't have to roll my own paging (calculating skip and limit parameters, which I guess is not hard) and call into the template directly, but I guess I can if that's the best choice.
I don't think this can be done in the way I'd hoped, but I've come up with a workaround. As background, we put all our methods to do data access in a DAO, and some delegate to the repository, some to the template.
Wrote a DAO method which takes our arbitrary filter string (which I have a utility that converts it to standard mongo JSON query syntax.
Wrap that in a BasicQuery to get a "countQuery".
Use that countQuery to get a total count of records using MongoTemplate#count(Query, Class)
Append my paging criteria to create a "pageQuery" using Query#with(Pageable)
Run the pageQuery with MongoTemplate#find(Query, Pageable)
Get the List<T> result from that, the Pageable that was used for the query and the count returned from the countQuery run, and construct a new PageImp to return to the caller.
Basically, this (DocDbDomain is a test domain class for testing out document db stuff):
Query countQuery = new BasicQuery(toMongoQueryString(filterString));
Query pageQuery = countQuery.with(pageRequest);
long total = template.count(countQuery, DocDbDomain.class);
List<DocDbDomain> content = template.find(pageQuery, DocDbDomain.class);
return new PageImpl<DocDbDomain>(content, pageRequest, total);
You can use the #Query annotation to execute an arbitrary query through a repository method:
interface PersonRepository extends Repository<Person, Long> {
#Query("{ 'firstname' : ?0 }")
Page<Person> findByCustomQuery(String firstname, Pageable pageable);
}
Generally speaking, #Query can contain any JSON query you can execute via the shell but with the ?0 kind of syntax to replace parameter values. You can find more information on the basic mechanism in the reference documentation.
In case you can't express your query within the #Query-Annotation, you can use the Spring Repository PageableExecutionUtils for your custom queries.
For example like this:
#Override
public Page<XXX> findSophisticatedXXX(/* params, ... */ #NotNull Pageable pageable) {
Query query = query(
where("...")
// ... sophisticated query ...
).with(pageable);
List<XXX> list = mongoOperations.find(query, XXX.class);
return PageableExecutionUtils.getPage(list, pageable,
() -> mongoOperations.count((Query.of(query).limit(-1).skip(-1), XXX.class));
}
Like in the original Spring Data Repository, the PageableExecutionUtils will do a separated count request and wrap it into a nice Page for you.
Here you can see that spring is doing the same.

Spring Data JPA finder for dynamic fields as Map

My requirement is to have few custom fields in the domain objects. These fields may vary as per the clients.
We are using Spring Data JPA to execute finders. Spring data implicitly provides finders for static fields of the domain and can also handle finders for the fields in the object graph.
I want to know if there is a way to find data on the custom fields? Can someone suggest me a strategy to achieve the same. Below is the sample of my domain class.
public class Employee{
private String name;
private String age;
private Map customeFields; (May vary as per client)
}
I was thinking of overriding QueryLookupStrategy and create my CustomJpaQuery on lines of PartTreeJpaQuery to achieve it. Is there any better approach? Does spring data jpa provides an easy mechanism to override query creation mechanism?
If you are using hibernate (not sure about other JPA implementations) you may add methods with #Query annotations like this:
#Query("select e from Employee as e where e.customeFields[:key] = :value")
List<Employee> findSomeHow(#Param("key") String key, #Param("value") String value)