How to make Groovy / Grails return a List of objects instead of a List of Lists of objects?

ubiquibacon picture ubiquibacon · Jun 21, 2012 · Viewed 11.8k times · Source

I have a class like this:

class Foo {
    static hasMany = [bars: Bar]
}

When I write:

Foo.getAll()

I get a list of Foo objects like this:

[ Foo1, Foo2, Foo3 ]

When I write:

Foo.getAll().bars

I get a list of lists of Bar object like this:

[ [ Bar1, Bar2 ], [ Bar2, Bar3 ], [ Bar1, Bar4 ] ] 

But what I want is a unique list of Bar objects like this:

[ Bar1, Bar2, Bar3, Bar4 ]

My end goal is to have a unique list of ids of the Bar object in the list above, like this:

[ 1, 2, 3, 4 ]

I have tried variations of the collect method and I have also tried the spread operator but I'm not having any luck.

Answer

Ted Naleid picture Ted Naleid · Jun 21, 2012

For generic groovy classes (i.e. non-GORM classes), David is correct that using flatten and unique is the best way to go.

In your example though, it looks like you're using GORM domain objects in a many-to-many relationship (otherwise you wouldn't need the uniqueness constraint).

For a domain class, you're best off using either HQL or a criteria to do this in one step. An additional advantage is that the SQL generated for it is much more efficient.

Here's the HQL for getting the unique Bar ids that are related to any Foo in a many-to-many relationship:

Bar.executeQuery("select distinct b.id from Foo f join f.bars b")

The criteria for this would look like:

Foo.withCriteria {
    bars {
        projections {
          distinct("id")
        }
    }
}

One "issue" with using this kind of method is that HQL is not supported in unit tests (and likely will never be) and Criteria queries with join table projections are broken in 2.0.4 unit tests. So any tests around this code would either need to be mocked or use an integration test.