Query in spring data mongo repository - java

I want to write custom query on spring data mongodb. Something like this:
public interface CarRepo extends MongoRepository<Car, String> {
#Query("select distinct(brand) from Car ")
public List<String> findDistinctBrand();
}
But it's throwing an error "Caused by: com.mongodb.util.JSONParseException: ". How can I achieve that?

MongoDB does not support distinct command.
It only supports returning distinct field values using the distinct command.
You need to use Mongodb template, for your results:
DBCollection colllection = mongoTemplate.getCollection("collectionName");
Criteria criteria = new Criteria();
criteria.where("your column").is("your value");
Query query = new Query();
query.addCriteria(criteria);
List list = mongoTemplate.getCollection("collectionName")
.distinct("source",query.getQueryObject());

You are using SQL to query in mongodb, but mongodb has its own query language. You need to write query in that language. As you are going to use distinct command you cannot user Query annotation or spring data query to do that. You need to create custom repository and execute distinct command using MongoTemplate.

Per the docs you should be able to accomplish this by simply defining the method in your repository interface, without the help of #Query:
public interface CarRepo extends MongoRepository<Car, String> {
public List<String> findDistinctBrand();
}

Related

Spring Find By Like Feature

I have a list of entities in my code (google.com, amazon.com, etc), and I would like to have my repository find an entity when I type feed it a string with a subdomain.
So basically, what repository function do I implement so I can run something like
public List<ValidDomainsEntity> findByCompanyDomainLike("www.google.com");
and have it return the entity with google.com in its
String companyDomain;
where the companyDomain = "google.com"
So in more layman's terms: My db contains URL's without the subdomain or prefix. What query do I use in spring's repository to find that URL when I put in a URL with a subdomain
Edit: Basically how I do the spring equivalent of
select * from valid_domains where 'www.amazon.com' LIKE CONCAT('%', companyDomain);
You can write it in several ways. First option is writing a native query.
#Query(value = "select * from valid_domains where 'www.amazon.com' LIKE CONCAT('%', :companyDomain", nativeQuery = true);
public List<ValidDomainsEntity> myQuery(#Param("companyDomain") String companyDomain);
Second option is writing a simple non native Query and use your Entiry class names and fields. For this you purpose you can use javax.persistence.EntityManager or #Query(value = "", nativeQuery = false). By default #Query is non native query, you dont have to write nativeQuery = true. I show also an EntityManager example.
#Autowired //Constructor dependency injection is more preferred instead of #Autowired
private EntityManager entityManager;
List<ValidDomain> query = entityManager.createQuery("SELECT new ValidDomain(d.id, d.domainName) from ValidDomain d where 'www.amazon.com' LIKE CONCAT('%', :variableName)", ValidDomain.class).getResultList();
Or you can also use EntityManager, entityManager.createNativeQuery() for creating native query.

Can somebody help me building up an #Query that can be used with MongoDB

I have laid out the Java architecture according to my requirement but is struggling with the formation of query part.
The architecture is as follows
Class AbcRequest{
List<Filters> filters;
}
Class Filters{
String abcCode;
List<String> abcType;
}
Class abcController{
getFilters(List<String>someList, boolean status, AbcRequest request){
for(Filters filter: request.getFilters(){
String abcCode = filter.getAbcCode();
List<String> abcTypes = filter.getAbcType();
}
}
}
Now I want to pass these values to a repository and get the list of required queries from DB based on it.
My query should have a condition like :
where ((someList in ('a','b') and status='false' and abcCode='8' and abcType in ('done','pending') OR (someList in ('a','b') and status='false' and abcCode='6' and abcType in ('pending'))
How to write a MongoDB #Query to get such a query out of the repository method.
It is a mixture of many 'AND' along with combination of 'OR'
Like for example :-- where (a AND b AND c AND d) OR (a AND e AND f AND d)
I know how to use simple OR with #Query:- Like building a query for example (where A=10 OR B=10)
#Query('$or' : [{A:10},{B:10}])
But query that I wanted to build is a bit complex and am struggling with it. Also I don't want to use Criteria because I have to deal with return types. Best is to use #Query and I have been instructed to use #Query as well.
Any help will be much appreciated.
Mayme you can try this:
Query query = new Query();
Criteria criteria = new Criteria();
Criteria a = new Criteria();
a.andOperator(Criteria.where("someList").in(Arrays.asList("A","B")),Criteria.where(
"status").is(false),Criteria.where("abcCode").is(6),....)
// B is the same as a
Criteria b = new Criteria();
//...
criteria.orOperator(a,b);
query.addCriteria(criteria);
I found a very good link to answer my own question : writing complex query in mongo DB
This will help with writing complex queries using #Query annotation for MongoDB.
This will also provide a vivid understanding of how to use AND and OR.
Thanks!

Spring data Derived Queries with Multiple Condition and one parameter

How can I create a derived query methods in Spring data which select result based on multiple conditions but with only one parameter.
List<Entity> findById1OrId2OrId3(String id1OrId2OrId3);
Something like this example.
I don't think it is possible with derived queries.
Alternatively,
#Query("from Entity e where e.id1 = ?0 or e.id2 = ?0 or e.id3 = ?0")
List<Entity> findById1OrId2OrId3(String singleId);
You can use "In" and make list of Ids then make a new derived query to achieve this

Hibernate - How to execute named native query without mapping to a specific class

I have a very complicated query that doesn't convert to HQL, so I must use SQL. I put my query into a NamedNativeQuery annotation. It "should" return a list of two values (List<Object[2]>). When I try to run, the session fails to load the query because I haven't defined a mapping or result class. I cannot create a simple class to map these values to because the annotations have to go in a specific DAO project and the code that is using the queries exists in its own project. (The DAO project is more general-purpose and the entities in that project map directly to tables in our database. I cannot just create a small class in this project to map to my query result because it wouldn't fit the schema of this project)
Is there a way for me to map the query results to a more generic class, or even better is there some way for me to just get a List<Object[]> back without having to map at all to anything particular? This is extremely frustrating that Hibernate has to work in this particular way when all I want to do is execute a query and get the result back as an array.
This is the code that I use for storing the result of a SQL query in a List<Object[]>. Maybe you can adapt it to what you need:
public List<Object[]> executeSelectQuery(String sqlQuery) {
List<Object[]> cleanedResults = new ArrayList<Object[]>();
SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sqlQuery);
List<Object[]> hibernateResults = query.list();
// Hibernate does not return always a List<Object[]>, but a list of strings or integers, so it is necessary to check the returned values
if (!hibernateResults.isEmpty()) {
if (hibernateResults.get(0) instanceof Object[]) {
cleanedResults = hibernateResults;
} else {
Object[] row;
// Use a 'for' because 'foreach' sometimes has casting exceptions converting to object
for (int i = 0; i < hibernateResults.size(); i++) {
row = new Object[1];
row[0] = hibernateResults.get(i);
cleanedResults.add(row);
}
}
}
return cleanedResults;
}
A NamedNativeQuery supports an addition annotation to allow you map the result to a POJO:
#SqlResultSetMapping(name="MyResult.Mapping", entities = {
#EntityResult(entityClass=MyResult.class, fields = {
#FieldResult(name="email", column="email"),
#FieldResult(name="name", column="name")
})
})
Then add resultSetMapping="MyResult.Mapping" to your NamedNativeQuery annotation.
I ended up not using NamedNativeQueries because they weren't working for me. Instead, I just used session.createSQLQuery with constant Strings, and it worked.
I probably didn't phrase my question properly. I could not use a #SqlResultSetMapping because I didn't have any classes to map to based on the structure of the code I am working with. My query has to come out as a List<Object[]> result, and there is no way to do that with NamedNativeQueries because Hibernate doesn't support it.

selecting maximum field of a column using query dsl predicate

Im new to query dsl.Im using Spring repositories to get the result set.And one case i have to get the maximum of a column and get the fields in to an entity.My predicate code is below.I get error once i run this code.
public static Predicate getMaximum(){
QUserDetails details = QUserDetails.userDetails;
return details.id.eq(details.id.max());
}
And this is how i fetch my resultset using spring jpa
public UserDetails findByCustomerId(Predicate predicate);
And this is the error i get:
org.springframework.data.mapping.PropertyReferenceException: No property find found for type com.example.entity.UserDetails.Can anyone help me acheive what i want here.
You have to define a QueryDslJpaRepository which adds implementation for QueryDslPredicateExecutor
http://docs.spring.io/spring-data/jpa/docs/1.5.0.M1/api/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.html
You can see a tutorial here:
http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-eight-adding-functionality-to-a-repository/
From the QueryDSL email group, apparently what you have to do to select the max ID is this:
from(entity).singleResult(entity.id.max())
So it's
JPAQuery jpaQuery = new JPAQuery(entityManager);
QEntity qEntity = QEntity.entity;
Long maxId = query.from(qEntity).singleResult(qEntity.id.max());

Categories