Projection on a MongoDb Query using Spring data and QueryDSL - spring

I have a Spring MVC/Spring Data / Mongo DB application.
I have setted up my environement according the the spring data documentation and my repositories work fine (I can execute queries with predicates)
I was wondering if it was possible to execute a type safe query (using Spring Data and QueryDSL) while making a projection (I want only a few fields of a very big document).
The QueryDSL documentation gives an example for Hibernate but states it can be done in all modules QueryDSL Documentation (but I haven't been able to find out how to do it with Mongo)
here's the code snippet for hibernate
class CustomerDTO {
#QueryProjection
public CustomerDTO(long id, String name){
...
}
QCustomer customer = QCustomer.customer;
JPQLQuery query = new HibernateQuery(session);
List<CustomerDTO> dtos = qry.from(customer).list(new QCustomerDTO(customer.id, customer.name));
Any Ideas ?

This is currently not supported. Feel free to add a ticket for it into our Issue tracker.
The Lucene and Mongodb modules of Querydsl support only direct projections from the query root, but for custom projections something could be figured out.

I've just built a projection like this:
Criteria c1 = Criteria.where("field.name").is("val")
Criteria projection = Criteria.where("field").is(1)
BasicQuery query = new BasicQuery(c1.getCriteriaObject(), projection.getCriteriaObject())

Related

Spring Data JPA + Bytecode Enhancement

Is it possible to load #*ToOne attributes eagerly using JPA interface(Entity Graphs) which are set lazy using #LazyToOne , #LazyGroup in the parent entity class and enabled bytecode enhancement ? I am trying to load such attributes eagerly using entity graph but it is firing another query for such #*ToOne attributes when an parent entity is queried.
Trying to have another way to override static fetch type in entity classes including #LazyToOne which was added with bytecode enhancement.
Using Spring 5.1.3 , Spring JPA 2.2 , Hibernate 5.4.19
Update : Data JPA is working as expected and i could see joins for the attributes which i am trying to fetch eagerly but those lazy attributes are not being initialised with the join query response and hibernate causing each query on referencing attributes which were annotated with #LazyToOneOption.NO_PROXY and was already fetched eagerly using entity graph in my repository.
How can i avoid this second select which is not even required since i got the that data eagerly from entity graph in JPA respository ??
Any help would be highly appreciated.
Entity Graphs just like Hibernate fetch profiles apply regardless of what annotations you have on the association. If it does not, maybe there is a bug in Spring Data or maybe even Hibernate. It's probably best if you create a new JIRA issue with a test case reproducing the problem.
Having said that, I think this is the perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
An example DTO model could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Long getId();
String getName();
Set<RoleDto> getRoles();
#EntityView(Role.class)
interface RoleDto {
#IdMapping
Long getId();
String getName();
}
// Other mappings
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Pagination in Spring using #RestController, but without using Spring Data Rest Pageable?

I know using Spring Data Rest I can use the in-built functionality of Pagination Like this
Page<Product> findByCategoryId(#RequestParam("id") Long id, Pageable pageable);
However, I am in project I am using Spring mvc #RestController and want to achive the same functionality
I tried like this:-
Session currentSession = entityManager.unwrap(Session.class);
Query<Product> theQuery = currentSession.createQuery("from Product", Product.class);
theQuery.setFirstResult((pageNumber-1) * pageSize); // This is 0 based
theQuery.setMaxResults(pageSize);
List<Product> dataList = theQuery.getResultList();
return dataList;
It works but I don't get the count of total number of records in the table.
And for UI pagination I need that.
So do I have to hit 2 queries everytime first like above then 1 query to fetch record size. (Which can cause data sync problems if records are updated)
Or
Is there a better way to achieve this in SINGLE QUERY
If you need the total number of records then you must create a second query.
You could do that in one query with a subquery but then you cannot use Entities as return type.
Regarding data sync problems: If you run both queries in the same transaction there is no problem.
Btw. why do you unwrap the Hiberante Session? There is no need for that in your example.

Spring Data- how to tell spring what entities to retrieve

If i have several entites, lets say :
#Entity
class Book{
String name;
Author author;
}
#Entity
class Author{
String name;
City hometown;
}
#Entity
class City{
String cityName;
}
If i want to retrieve all the books, if i use classic JPA Repository and Spring Data and just do a findAll(), it will get me all the books with all the Authors with all their home towns. I know i can use #JsonIgnore, but i think that only prevents whats being returned, not whats being looked up in the database. And also i have methods that DO want to return both books and authors, so #JsonIgnore -ing does not work for me. Is there anything like this ? To tell Spring Data what to look up and what to return ? Any links or guides or methods i don't know of, would be appreciated.
Spring Data has the concept of 'projections' which allow you to return different representations of the same Entity.
Official Documentation:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
Where a Projection is a 'closed' projection (a projection interface whose accessor methods all match properties of the target aggregate) then the documentation notes that additionally:
Spring Data can optimize the query execution [to select only the relevant fields], because we know about
all the attributes that are needed to back the projection proxy
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces.closed
Spring Data also allows for Projections to be specified dynamically at runtime. See further:
https://github.com/spring-projects/spring-data-commons/blob/master/src/main/asciidoc/repository-projections.adoc#dynamic-projections
First mark your relations as LAZY
Then specify what data needs to be fetched on a per-query basis.
See for example:
https://vladmihalcea.com/eager-fetching-is-a-code-smell/

Spring data mongorepository, find by inner object field

I am developing a simple Social network and need help with mongorepository query.
I have 2 documents:
#Document(collection = "post")
public class Post {
...........
#DBRef
#Field("settings")
private Settings settings;
and
#Document(collection = "settings")
public class Settings {
..............
#Field("privacy_settings")
private PrivacySettings privacySettings;
}
PrivacySettings is an enum with settings ONLY_ME, EVERYONE, FRIENDS.
And the situation is: a friend is viewing on my page and he can see my posts with correct privacy settings(etc. he can see only posts with PrivacySettings: EVERYONE, FRIENDS, but not the ONLY_ME).
Ideas, how to resolve this problem? How to create a correct query?
Solution 1
In Mongo, you can't query of DbRef fields except for Id as no join is supported in this. As read operation is very high I will recommend you to embed part of Setting document in Post instead of referencing it. As mongo DB design suggest if read > write you should embed the document. In this case, the query will be simple.
Solution 2
You can fire two DB queries 1st on Setting document to get the Setting with EVERYONE, FRIENDS the make query on Post document to get all post with Setting in query.
Solution 3
You can use QueryDSL for query on DbRef object easily for reference see this.

How to get column names of a table using spring data jpa

I am using spring boot, spring data JPA, I am searching for solution to get all column names of a given table. But could not found as per my requirements
Not want a solution with native query.Looking for general solution using spring data abstraction.
I am able to get the column names using normal java but i want to fetch them using spring data JPA.
they are several ways
public interface TableMetadataRepository extends JpaRepository<TableMetadata, TableMetadataKey>
{
TableMetadata findByTableName(String tableName);
}
then you can go for
List<TableMetadata> metadata = tableMetadataRepository.findAll()
TableMetadata metadataofspecifictable = tableMetadataRepository.findByTableName("urtable");

Resources