in my method Java,
I would like to pass as a parameter to my collection MongoDB a complex query like this one:
{"$or": [{"$and": [{"contextID": "AKKA"}, {"messageID": "PIPPO"}]},
{"$and": [{"domain": "Niguarda"}, {"hostName": {"$ne": "hostServer"}}]}
]
}
The string that contains the query is variable and passed as parameter in query string.
I tried to pass the query as parameter to method criteria
(queryDB.criteria("
{"$or": [
{"$and": [{"contextID": "AKKA"}, {"messageID": "PIPPO"}]},
{"$and": [{"domain": "Niguarda"}, {"hostName": {"$ne": "hostServer"}}]}]
}"
)
but it does not work.
Any suggestions?
What you're trying to do would be
Query q = dao.createQuery();
q.or(
q.and(new Criteria[]{ dao.createQuery().filter("contextID").equal("AKKA"),
dao.createQuery().filter("messageID").equal("PIPPO") }),
q.and(new Criteria[]{ dao.createQuery().filter("domain").equal("Niguarda"),
dao.createQuery().filter("hostname").notEqual("hostServer") })
);
This is now the code (it's works fine but I abandoned morphia):
public long count(String query) throws Exception {
DB db = mongoClient.getDB(mongoDBName);
DBCollection dbCollection = db.getCollection(mongoDBCollection);
DBObject dbObjQuery;
long l = 0;
try {
if (!(query == null)) {
dbObjQuery = (DBObject) JSON.parse(query);
l = dbCollection.find(dbObjQuery).count();
} else {
l = dbCollection.find().count();
}
} catch (Exception e) {
} finally {
}
return l;
}
There is another way to do this with morphia?
Related
I have a very strange problem. I create 3 entities with the following data:
CCB ccb1 = new Ccb(1)
CCB ccb2 = new Ccb(2)
CCB ccb3 = new Ccb(3)
Where the parameter (Long) is the object id.
Then, when wanting to create a list with the between clause, it is created with size = 0:
ConcurrentLinkedQueue<Long> ccbIds = new ConcurrentLinkedQueue(
Ccb.createCriteria().list {
between("id", 1, 5)
projections {
id()
}
}
)
I've tried this alternative and it doesn't work either:
ConcurrentLinkedQueue<Long> ccbIds = new ConcurrentLinkedQueue(
Ccb.createCriteria().list {
between("id", "1", "5")
projections {
id()
}
}
)
The incredible thing is that if I replace the between with the eq:
ConcurrentLinkedQueue<Long> ccbIds = new ConcurrentLinkedQueue(
Ccb.createCriteria().list {
eq("id", 2)
projections {
id()
}
}
)
Now the list returns me the element with id 2!
I can't understand where is the error.
Thanks!
EDIT:
Config of DataSource.groovy:
dataSource {
dbCreate = "create-drop"
driverClassName = "org.h2.Driver"
dialect = "org.hibernate.dialect.H2Dialect"
url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE"
}
try this:
Ccb.createCriteria().list {
between("id", 1l, 5l)
projections {
property('id')
}
}
or:
Ccb.createCriteria().list {
and{
between("id", 1l, 5l)
}
projections {
property('id')
}
}
Can't you stream the list and filter by ID?
def list = foolist.stream().filter(f -> f.getId() > 0 && f.getId() < 4).collect(Collectors.toList())
After run different tests, I came to the conclusion that it is a bug in Grails when using the H2 storage. With SQL it works fine.
I have a problem in a CallableStatement that execute a stored procedure query which accept a parameter.
I have a list of string that contains the query like:
{call query5_immatricolati(?)}
I have a list of string that contains the parameter like
String cds = "L-INF";
I have no SQL syntax error when I run but the result set doesn't have any value.
The expected result of the execution is that i could create an object by receiving data from the result set.
Here is the code:
for (int i = 0; i < INDICATORI.getInstance().getListaIndicatori().size();) {
for (int j = 0; j < INDICATORI.getInstance().getListaQuery().size();) {
if (INDICATORI.getInstance().getListaIndicatori().get(i).equals("iC00a")) {
for (String cds : CDS.getInstance().getCds().values()) {
ArrayList<indicatore> lista = new ArrayList<indicatore>();
String query = INDICATORI.getInstance().getListaQuery().get(j);
try {
CallableStatement cb = DB.getInstance().getConnection().prepareCall(query);
cb.setString(1, cds);
DB.getInstance().setResultSet(cb.executeQuery());
} catch (SQLException e) {
e.printStackTrace();
}
try {
while (DB.getInstance().getResultSet().next()) {
iC00a obj = new iC00a();
obj.setId(counter);
obj.setAnnoIscrizione(DB.getInstance().getResultSet().getString(1));
obj.setIscrittiPrimoAnno(DB.getInstance().getResultSet().getInt(2));
lista.add(obj);
counter++;
}
} catch (SQLException e) {
e.printStackTrace();
}
map.getInstance().getMap().put(INDICATORI.getInstance().getListaIndicatori().get(i)+cds, lista);
counter=0;
}
}
i++;
j++;
}
}
I tried to manually set in cb.setString(1,cds) the value like cb.setString(1,"L-INF") AND IT WORKS !!!
But I can't set manually the parameter, I need to iterate with for each loop each string and dynamically insert as parameter.
Why if I set the parameter manually like a string it works instead if i give a string variable not ?
Could anyone tell me what I'm doing wrong?
After a lot of attempts, I've found the solution.
The problem is in your variable cdsbecause it could have white spaces before or after.
Try:
cb.setString(1,cds.strip());
For me it worked.
The principe is like in StackOverFlow - every question has tags. And I need to display these tags by frequency of mentions for last day.
public List<TagDto> getAllTagsByCount() {
List<TagDto> tagDtos = new ArrayList<>();
try {
tagDtos = entityManager.createQuery("SELECT t.id, t.name FROM Tag t") // have no idea how to write such query
.unwrap(Query.class)
.setResultTransformer(new ResultTransformer() {
#Override
public Object transformTuple(Object[] objects, String[] strings) {
return TagDto.builder()
.id((Long) objects[0])
.name((String) objects[1])
.build();
}
#Override
public List transformList(List list) {
return list;
}
})
.getResultList();
} catch (Exception e) {
e.printStackTrace();
}
return tagDtos;
}
If u'll need some additional part of code, please let me know
What you are looking for is probably something like the following
List<Tuple> tuple = entityManager.createQuery("SELECT t.name, COUNT(*) FROM Tag t WHERE t.date BETWEEN :yesterday AND :tomorrow GROUP BY t.name")
.setParameter("yesterday", LocalDateTime.now().minus(1, ChronoUnit.DAYS).with(LocalTime.of(0, 0, 0))
.setParameter("tomorrow", LocalDateTime.now().plus(1, ChronoUnit.DAYS).with(LocalTime.of(0, 0, 0))
.getResultList();
You do not seem to have basic SQL knowledge though, so I would recommend you try to learn SQL first.
I am using hibernate spring where I need to generate query on a condition.
DAO.java
public ReturnData updateUserDetails(Users users, String mailID)
{
if(!users.getImageURL().equals(""))
{
Query query = this.sessionFactory.getCurrentSession().createQuery("UPDATE users SET emailID=:email_ID, name=:name, imageURL=:imageURL WHERE emailID=:emailID")
//setString....
}
else
{
Query query = this.sessionFactory.getCurrentSession().createQuery("UPDATE users SET emailID=:email_ID, name=:name WHERE emailID=:emailID")
//setString....
}
}
In the above code, I check if image also has been uploaded or not. On the basis of this condition, I have to dynamically generate query. I have to rewrite the whole code for query+execution 2 times. Is it the good way, or is there any better way to do this?
You can dynamically append the query conditions to the query string if they are not null. After getting the final list of conditions, you can create Hibernate query.
StringBuilder sqlQuery = new StringBuilder();
Map<String,Object> parameters = new HashMap<String,Object>();
boolean isFirstSearchCriterion = true;
sqlQuery.append("UPDATE users");
if(email_ID!= null && !email_ID.trim().equals("")) {
if(isFirstSearchCriterion) {
sqlQuery.append(" set emailID= :email_ID");
} else {
sqlQuery.append(" and emailID= :email_ID");
}
parameters.put("email_ID",email_ID);
isFirstSearchCriterion = false;
}
if(name!= null && !name.trim().equals("")) {
if(isFirstSearchCriterion) {
sqlQuery.append(" set name= :name");
} else {
sqlQuery.append(" and name= :name");
}
parameters.put("name",name);
isFirstSearchCriterion = false;
}
if(imageURL!= null && !imageURL.trim().equals("")) {
if(isFirstSearchCriterion) {
sqlQuery.append(" set imageURL= :imageURL");
} else {
sqlQuery.append(" and imageURL= :imageURL");
}
parameters.put("imageURL",imageURL);
isFirstSearchCriterion = false;
}
Query query = this.sessionFactory.getCurrentSession().createQuery(sqlQuery);
Set<String> parameterSet = parameters.keySet();
for (Iterator<String> it = parameterSet.iterator(); it.hasNext();) {
String parameter = it.next();
query.setParameter(parameter, parameters.get(parameter));
}
You can simply do without checking empty String, if user has image url it will add in column or else empty url will be pass on.
public ReturnData updateUserDetails(Users users, String mailID)
{
Query query = this.sessionFactory.getCurrentSession().createQuery("UPDATE users SET emailID=:email_ID, name=:name, imageURL=:imageURL WHERE emailID=:emailID")
query.setParameter("imageURL",users.getImageURL(), Hibernate.STRING);
}
Using Spring JDBC I find myself doing stuff like this all the time:
NamedParameterJdbcTemplat njt = ...;
String SQL = "SELECT blah FROM blah_table WHERE column = :condition";
SqlParameterSource params = new MapSqlParameterSource('condition', variableName);
List<Integer> rows = njt.query(SQL, params, Integer.class);
if(rows.size() == 0)
{
//record did not exist, whew avoided index out of bounds exception
}
//do something with rows.get(0);
There has to be a better way right?
You could use queryForObject, e.g.:
Integer i = null;
try {
i = template.queryForObject(sql, Integer.class, args);
} catch (EmptyResultDataAccessException e) { // zero rows
}
You could write your own wrapper method to deal with the EmptyResultDataAccessException and make it cleaner.