Grails Gorm MongoDB index Embedded String Map - grails

I wanted to make some translatable content with rest service so i decided to create collection with this structure. But I can't find BSON by value from String Map.
class LocalizableString{
static mapWith = "mongo"
ObjectId id
Map<String, String> values = new HashMap<String, String>();
}
Then i wanted to get like this. But it works like join query.
def list = LocalizableString.createCriteria().list {
values{ like('value',"%${value}%") }
}
Here is similar plain mongo example. But how can i implement it with gorm mongoDB http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Example
Is there any solution for that ?

class BaseService {
def findByLocalizableString(def domainClass ,def query , def field ,def params = null) {
def q = new BasicDBObject()
def queryList = []
def allowedLanguages = ConfigurationHolder.config.grails.localizableString.allowedLanguages
allowedLanguages.each { locale ->
queryList.add(new BasicDBObject("values.${locale}", new BasicDBObject('$regex', /.*${query}.*/)))
}
q.put('$or',queryList)
def lsc = LocalizableString.collection.find(q)
def list = lsc.hasNext() ? domainClass.createCriteria().list(params) {
or {
while (lsc.hasNext()) {
def n = lsc.next()
eq("${field}",n._id)
}
}
} : null
return list
}
}

I'm not 100% on this, but I'm fairly certain the Mongo GORM plugin does not work with criteria relation traversal, which is what this looks like (despite not really being like that).
From mongoGorm website (http://blog.mongodb.org/post/18510469058/grails-in-the-land-of-mongodb):
Some of the GORM features that are not supported include:
Criteria queries on associations
HQL
Groovy SQL
So you may need to rethink the Map structure you have as a data model here :/ Anyone more experienced can weigh in?

Related

Grails createCriteria not returning any results

I'm trying to use the createCriteria in a grails application to return some rows from a DB. I'm not getting any results.
def query = {
ilike('fullName','%${params.term}%')
projections {
property('id')
property('fullName')
}
}
def plist = Patient.createCriteria().list(query)
def patientSelectList = []
plist.each {
def pMap = [:]
pMap.put("id", it[0])
pMap.put("label", it[1])
pMap.put("value", it[1])
patientSelectList.add(pMap)
}
the fields i'm looking for exist as the following snippet returns results but is very slow.
def patientList = Patient.getAll()
def patientSelectList = []
patientList.each { patient ->
if (patient.fullName.toLowerCase().contains(params.term.toLowerCase()) ) {
def pMap = [:]
pMap.put("id", patient.id)
pMap.put("label", patient.fullName)
patientSelectList.add(pMap)
}
}
return patientSelectList
thanks for anyhelp
I had my Db fields encryted with jasypt. Removing the encryption on the field I needed to query fixed the issue!
You're using a String rather than a GString in the ilike() parameter, so params.term is not being evaluated. To use a GString, use double-quotes instead.
ilike('fullName',"%${params.term}%")
Also make sure % is an appropriate wildcard character for your database (it probably is).

GORM where query on an embedded object

I have domain classes A and B as follows:
class A {
String prop1
String prop2
B prop3
static embedded = ['prop3']
}
class B {
String prop4
String prop5
}
When I want to query like this:
def q = A.where { prop3.prop4 == 'bla' }
def list = q.list()
I get the following exception:
Cannot get property 'javaClass' on null object. Stacktrace follows:
on the "def q = A.where ..." line.
Any clue what's the problem? I've checked this:
http://grails.1312388.n4.nabble.com/GORM-embedded-object-issue-td1379137.html
but how to "just call them directly" is not quite clear to me. Any other way of querying the embedded objects in GORM?
I finally gave up on the where query and went with the DetachedCriteria approach. Gives me the same flexibility as the where queries, but works with embedded domain objects:
def criteria = new DetachedCriteria(A).build {
eq 'prop1', 'bla2'
}
criteria = criteria.build {
eq 'prop3.prop4', 'bla'
}
def list = criteria.list()
What do you get if you do (assuming B is in src/groovy)
def q = A.where { prop3 == new B(prop4: 'bla') }
def list = q.list()
Embedded components are persisted inside the main domain class (owner) itself. It can be accessed directly using any dynamic finder as you do directly on a domain object.
The above can also be represented in dynamic finders as:
A.findAllByProp3(new B(prop4: 'bla'))

Grails - How to get list of distinct User Objects

Is there a way that, i can get list of distinct User objects(based on username). And still get result as a List of User Objects rather than, List of username's.
My code is
def criteria = User.createCriteria()
def users = criteria.list() {
projections {
distinct("username")
}
setResultTransformer(CriteriaSpecification.ROOT_ENTITY)
}
return users
Currently am getting List of the usernames, not User.
Ya projection is like filtering and selecting by username you should change it to
def criteria = User.createCriteria()
def users = criteria.listDistinct() {
projections {
groupProperty("username")
}
}
return users
JOB DONE!
One of these should work - I haven't tested any of them, I leave that up to you :)
User.list().unique()
User.list().unique() with the equals() method on the User domain class overridden to compare objects using the username
User.list().unique { it.username } (might need toArray() after list())
def criteria = User.createCriteria()
def users = criteria.list() {
projections {
distinct("username")
}
setResultTransformer(CriteriaSpecification.ROOT_ENTITY)
}
Just replace setResultTransformer(CriteriaSpecification.ROOT_ENTITY) with resultTransformer(ALIAS_TO_ENTITY_MAP). You will get a list of string as a result
otherwise just replace .list with .listDistinct and use do not need distinct("username"), just can be property("username");
Usually people get problems with pagination. not results. If you already had something like:
User.createCriteria().list([max:params.max,offset:params.offset],{
createAlias("others", "others", CriteriaSpecification.LEFT_JOIN);
ilike("others.firstName", "%${query}%");
});
It could result in row duplicates. Because .listDistinct() does not support pagination, just add
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
So query will look like this:
User.createCriteria().list([max:params.max,offset:params.offset],{
resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
createAlias("others", "others", CriteriaSpecification.LEFT_JOIN);
ilike("others.firstName", "%${query}%");
});
Where ever you got a collection (list, array, ...) (I don't know if work with any type of collection, but work in all that i could test). Use unique{ it.property }:
Example:
def users = []
for (def room in rooms) {
users.addAll(room.users)
}
return users.unique{ it.id }
Using where query(Detached criteria):
def userListQuery = User.where{
// Your search criteria
}
def userList = userListQuery.list().unique{ it.username }
it should result one query for distinct results.
This will get you the distinct user object based on userName
def userInstance = User.list().unique{ it.user_name}

gorm projection and loss of metainformation

When using projection on the properties, the result is returned as the list with the elements in the same sequence as that defined in the projections block. At the same time the property names are missing from the list and that is really disadvantageous to the developer as the result would be passed along and the caller needs to know what value belongs to which property. Is there a way to return a map from the Criteria query with property name as the key to the value?
so, the following code:
def c = Trade.createCriteria()
def remicTrades = c.list {
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
This returns:
[['book1', 'author1']['book2', 'author2']]
Instead I would like it to return:
[[book:'book1', author:'author1'][book:'book2', author:'author2']]
I know I can arrange this way after getting the result but I earnestly feel that the property alias should have been used by the criteria to return a list of map that mimics the result of the SQL query and not a bland list.
Duplicate: Grails queries with criteria: how to get back a map with column?
And the corresponding answer (and solution): https://stackoverflow.com/a/16409512/1263227
Use resultTransformer.
import org.hibernate.criterion.CriteriaSpecification
Trade.withCriteria {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
Agree with your question reasoning, this really should be part of the core GORM solution. That said, here's my workaround;
def props = ['name','phone']
def query = Person.where {}.projections {
props.each{
property(it)
}
}
def people = query.list().collect{ row->
def cols = [:]
row.eachWithIndex{colVal, ind->
cols[props[ind]] = colVal
}
cols
}
println people // shows [['name':'John','phone':'5551212'],['name':'Magdalena','phone':'5552423']]

Grails criteria builder

I have the folowing:
class Store{
String name
}
class Shop{
String name
Store store
}
My criteria builder:
def c = Shop.createCriteria()
def results = c.list {
like("name", "Harrods")
like("store.name", "McDonals")
}
I'm sure this is invalid cause i'v tested it. How can i manage to use criteriaBuilder and do this: like("store.name", "McDonals")?
Looking forward to get any help,
John
Since you're querying an association, try:
def results = c.list {
like('name', 'Harrods')
store {
like('name', 'McDonals')
}
}
This will do an conjoined query between name and store.name.
Check out the documentation Looks like you need to use a % for your like clause.

Resources