Grails searchable returns domain but relation is null - grails

I have 3 domains: A, B, C.
A and C have many-to-many relationship through B.
A and C are searchable.
When I search and get list of A domain all the fields in A are accessible, however relation field is always 'null'. Why I can't access relational field? Why do I get 'null'? If I access object directly, I see a relation, but when searchable returns A domain, I get 'null' on a relation field.
P.S: I tried to make B searchable but it looks like searchable having issue with indexing it on top of that I don't see any point in indexing B since it exists for the sake of many-to-many relationship only.
Please I need help with it. I need to be able to get to C via A on a searchable return.
Thank you.
[Update]: I made a prototype project today (small DB) and made domain B searchable. Now I can access relational field. However in my real project, I don't want to make B searchable since database is big and indexing takes too long. Is there a way around it?

You can refrash all instance in result list or use reload:true property for seach method
searchableService.search(query,[reload:true])
You can find full list of options: http://grails.org/Searchable+Plugin+-+Methods+-+search
reload - If true, reloads the objects from the database, attaching them to a Hibernate session, otherwise the objects are reconstructed from the index. Default is false

Ok, I believe I solved my issue.
First checkout link to a similar question: Grails searchable plugin -- Please give GalmWing some credit.
My solution is following, I am implementing my own controller and following piece of code implements searchable service call:
if (params.q) {
try{
def searchResults = searchableService.search(params.q, params)
searchResults.results.each {
it.refresh()
}
return [carInstanceList:searchResults.results, carInstanceTotal:searchResults.total]
} catch (SearchEngineQueryParseException ex) {
return [parseException: true]
}
As you can see I have a loop where on each item of domain "A" I do refresh. Now refresh gets real record from DB with all the links. Now I return list into GSP and it extracts all of "C" domains associated with the "A" domain.
Now this way you might get performance penalty, but in my case searchable is actually not able to index "B" domain, it is working for a while and then crashes, so I don't have another choice, at least for now.

Related

Exclude null values from GraphQL query

Disclaimer, I am still a noob in GraphQL.
Apologies for the long post, but I need to give as much information as possible to explain my issue.
I am currently trying to query my Neo4j using GraphQL and then tabulate the data using ReTool.
I managed to do most of the work but when I query the database, I also get the null values.
You can access the sandbox below to test yourself a probable solution.
https://codesandbox.io/s/great-marco-coy3k
The query I am using is the following:
query {
people{
child{
firstname{
name
}
middlename{
name
}
lastname{
name
}
phone{
name
}
email{
name
}
dob{
name
}
eid{
name
}
}
}
}
As you can see, I get back a mixture of null and none-null values.
What I would like to get back is the children that has data in them and ignore the null ones. The reason for that is when I try to populate my table, the null values appear there too.
I need to stress on the fact that I'd still need to retrieve "child" even if one or more of the objects are null as depicted in the image below:
While doing some research, I noticed that other people have the same problem I am facing (example), but most replies said there is no direct solution to this problem, many talked about adjusting the resolver which I am not sure how to do. The resolver file was already set by Neo4j Sandbox automatically and I don't know how to adjust it.
To provide more information regarding the root cause of the problem, you can check the Neo4j schema below:
As you can see, the two-person nodes that have the relationship MASTER_OF and CHILD_OF are similar.
When I query people{child{firstname name}...}
I get the value of the node that has a IN CHILD_OF relationship and null for the node that has IN MASTER_OF relationship.
As far as I understand, you are not sure what each value will return null : it may or it may not be null. In this case it is impossible to adjust your schema to only contain non-null values. You would have to deal with it in the frontend and completely exclude null values there.

PagedResultList .size() and .getTotalCount() return different values in grails gorm

I have the following code
PagedResultList res = myService.getPage(paginateParams, ...)
println res.size() // returns 2
println res.getTotalCount() // returns 1
getPage looks like:
def criteria = MyDomain.createCriteria()
criteria.list(max: paginateParams.max, offset: paginateParams.offset) { // max is 10, offset is 0, sortBy is updatedAt and sortOrder is desc
eq('org', org)
order(paginateParams.sortBy, paginateParams.sortOrder)
}
why do the two method return different values? The documentation doesn't explain the difference, but does mention that getTotalCount is for number of records
currently on grails 2.4.5
edits:
println on res prints out:
res: [
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a,
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a]
Yes, res has a SINGLE object twice - that's the bug I'm trying to fix. How do I know that? I have an primary key on MyDomain's ID, and when I inspect the database, it's also showing one record for this particular org (see my criteria)
edit 2: I found this comment (http://docs.grails.org/2.4.5/ref/Domain%20Classes/createCriteria.html)
listDistinct If subqueries or associations are used, one may end up
with the same row multiple times in the result set. In Hibernate one
would do a "CriteriaSpecification.DISTINCT_ROOT_ENTITY". In Grails one
can do it by just using this method.
Which, if I understand correctly, is their way of saying "list" method doesn't work in this scenario, use listDistinct instead but then they go on to warn:
The listDistinct() method does not work well with the pagination
options maxResult and firstResult. If you need distinct results with
pagination, we currently recommend that you use HQL. You can find out
more information from this blog post.
However, the blog post is a dead link.
Related: GORM createCriteria and list do not return the same results : what can I do?
Not related to actual problem after question edited but this quote seems useful
Generally PagedResultList .size() perform size() on resultList property (in-memory object represent database record), while .getTotalCount() do count query against database. If this two value didn't match your list may contain duplicate.
After viewing related issues (GORM createCriteria and list do not return the same results : what can I do?) I determined that there were several approaches:
Use grails projection groupBy('id') - doesn't work b/c i need the entire object
USe HSQL - Domain.executeQuery - actually this didn't work for my scenario very well because this returns a list, whereas criteria.list returns a PagedResultList from which I previously got totalCount. This solution had me learning HSQL and also made me break up my existing logic into two components - one that returned PagedResultList and one that didn't
Simply keep a set of IDs as I process my PagedResultList and make sure that I didn't have any duplicates.
I ended up going with option 3 because it was quick, didn't require me to learn a new language (HSQL) and I felt that I could easily write the code to do it and I'm not limited by the CPU to do such a unique ID check.

grails: how to properly edit/update a collection?

I just wasted half a day trying to figure this out, reading about some workarounds, and thinking "it can't be that bad - there must be a straightforward to do edit a collection in Grails, whethere using scaffolded views or my own."
Let's say I have this domain object:
class TreeGroup {
String name
List<Tree> trees
static hasMany = ['trees': MyTree]
}
Just to explain the choice of data structure - I need my records to be unique, but in the order I set. That's why I chose List, AFAIK one cannot rely on order in a Set. So there are 2 pieces to this question - 1) how to remove from any Collection, for example a Set, 2) is List the best replacement for Set in this context (preserving order).
I want to be able to create a group record with no trees in it and make 4 updates:
edit/save
edit the group record to reference 2 trees A and B
add another tree C
remove A
remove B and C
And obviously, I want the desired state after every step. Currently though, I can only add records, and if I even edit/save to list, the list elements are added to it again.
I am using the multiple select tag for this. It looks like this:
<g:select name="trees" from="${allTrees}" optionKey="id"
multiple="true" class="many-to-many"
value="${trees ? trees*.id : treeGroupInstance?.trees*.id}" />
and that's fine, in the sense that it generates an HTTP header with these variables on update:
_method:PUT
version:19
name:d5
trees:1
_action_update:Update
But the data binder only adds new elements, it never lets you edit a list.
What is the cleanest way to do it ? Is it me, not reading something obvious, or is this a design flaw of grails data binding (and of so, when/how will it be fixed) ?
Is there a way perhaps via a hidden HTTP parameter to clear the list before (re)adding elements ?
Thanks
I ended up doing this:
private repopulate(def domainObject, String propertyName, Class domainKlaz) {
if (params[propertyName] != null) {
domainObject[propertyName].clear()
domainObject[propertyName].addAll(
params[propertyName].collect { domainKlaz.get(it) }
)
}
}
and I am calling it in update controller method before save(), for every collection. OMG how ugly.

GORM mapping: make an index unique

I'm feeling a little slow today. I'm trying to do something that I think is very simple. I have a Domain class with a property called 'name'. I want 'name' to have an index, and I want the index to require that the 'name' is unique. I've set the unique constraint and tried creating an index. I can't make sense out of the Gorm docs as to how I add the unique attribute to the index. Here's some code:
class Project {
String name
static hasMany = [things:Things]
static mapping = {
name index:'name_idx'
}
static constraints = {
name(unique:true)
}
}
All is well with the above, except when do "show indexes from project" in mysql it shows my name key as not unique. I know the problem is that I am not specifying unique in the mapping, but quite frankly the docs for gorm are making my head hurt. I see all kinds of stuff about columns, but I can't find a single example anywhere on the web that shows what I want to do. I don't need complex mappings or compound keys, I just want to know the syntax to add the unique attribute to the mapping declaration above. Any advice welcome.
I also did a grails export-schema and see the following:
create index name_idx on project (name);
Nothing in that to indicate this index requires unique values
A related followup question would be once I succeed in making that index unique, what type of error should I expect when I go to save a Project instance and the name is not unique? Is there a specific exception thrown? I realize that even if I check that a given 'name' is unique there's still a possibility that by the time I save it there may be a row with that name.
I'm quite sure the syntax to do what I want is simple but I just can't find a simple example to educate myself with. I've been to this page but it doesn't explain HOW the uniqueness is enforced. I'd like to enforce it at the name index level.
The indexColumn allows additional options to be configured. This may be what you're looking for.
static mapping = {
name indexColumn:[name:'name_idx', unique:true]
}
Grails Documentation for indexColumn
If you put only the unique constraint the GORM send DDL to create an unique index on database.
static constraints = {
name nullable: false, unique: true
}

Lazy fetching of objects using FindAllBy , for the first time

When I use criteria queries, the result contains array list of lazy initialized objects. that is, the list has values with handler org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistLazyInitializer.
This prevent me from doing any array operation (minus, remove etc) in it. When I use, GORM methods, I get array list of actual object types. How can I get the actual objects in criteria query?
The code is listed below.
availableTypes = Type.withCriteria() {
'in'("roleFrom", from)
'in'("roleTo", to)
}
availableTypes (an array list) has one value , but not actual object but value with a handler of GroovyAwareJavassistLazyInitializer
availableTypes (an array list) has values with type Type
availableTypes = Type.findByRoleFrom(from)
---------- Update ----------
I did further troubleshooting, and this is what I found. Probably the above description might be misleading, but I kept it in case it helps.
When using findAllBy for the first time, I get proxy objects rather than the actual instance. Then, I invoke the method through an ajax call, the actual instance is loaded (anything to do with cache loading??). When I refresh the page, it again loads the proxy
def typeFrom = Type.findAllByParty(partyFrom)
there is another use of findAllBy in the same method, which always returns actual instances.
def relFrom = Relation.findAllByParty(partyFrom)
When compared the two classes, the attribute 'party' of class Roles is part of a 1-m relation. like
class Role {
RoleType roleType
LocalDate validFrom
LocalDate validTo
static belongsTo = [party : Party ]
...
}
I know if I do statement like Party.findAll(), the role instances would be proxy till they access. But, when using gorm directly on the class (Role), why I am getting the proxy objects ???
thanks for the help.
thanks.
Turns out are a couple of possible solutions which I came across but didn't try, such as
Overloading the equals method so that the proxy and the domain
object use a primary key instead of the hashCode for equality
Using a join query so that you get actual instances back and not proxies
GrailsHibernateUtil.unwrapProxy(o)
HibernateProxyHelper.getClassWithoutInitializingProxy(object)
One solution that worked for me was to specify lazy loading to be false in the domain object mapping.
History of this problem seems to be discussed here: GRAILS-4614
See also: eager load

Resources