Question

Hoping for some guidance.

Consider this snippet:

val q = (for {
    (d, o) <- dx innerJoin ox on (_.user === _.id)
   } yield(d,o))

  "div" #>  q.map { case (x, y) =>
  {
       ".dF1 *" #> x.name &
       ".dF2 *" #> y.id
  }
}

in this query, I have two tables, where table "ox" is a list of people, and "dx" is a list of items associated with those people. As it is written, it works good, but I end up creating one row for each item that a person has. So assume three users, first two have two items, and last one has 1, i get five rows:

<div class="dF1">[user1]</div><div class="dF2">[item1]</div>
<div class="dF1">[user1]</div><div class="dF2">[item2]</div>
<div class="dF1">[user2]</div><div class="dF2">[item1]</div>
<div class="dF1">[user2[</div><div class="dF2">[item2]</div>
<div class="dF1">[user3]</div><div class="dF2">[item3]</div>

What I'd like to do is create a single row for each user, and inside of the dF2 field create multiple divs, one for each item. The layout would then be:

<div class="dF1">[user1]</div><div class="dF2">[item1] [item2]</div>
<div class="dF1">[user2]</div><div class="dF2">[item1] [item2]</div>
<div class="dF1">[user3]</div><div class="dF2">[item1]</div>

How can I do this? Do I need to use an intermediary collection?

Was it helpful?

Solution

You have two options here, you can either use the database to return a collection grouped by a field or you can use Scala to group your collection. If you use the database, you will be limited to grouping by a field, like x.name, but your execution will likely be more efficient. If you group with Scala you'll be able to group by the entire object x, but you will end up doing more processing and object creation. You'd need to decide which is best for you.

Now, that said - let's assume we're using Scala. You would do something like this:

"div" #>  q.groupBy(_._1).map { case (x, y) =>
  {
       ".dF1 *" #> x.name &
       ".dF2 *" #> y.map{ case (x2, y2) => y2.id}.mkString(" ") 
  }
}

Instead of working directly with the List containing D and O from your query, the groupBy will create a list of type: Map[D, List[(D, O)]]. In the example above, I am just combining the id field of your o into a single string to output which looked like the example you requested.

Instead of a single string, you could also have your second map return a CssSel to do further transformations. This example which will look for <div class="dF2SubDiv"></div> nested in the div that has the class dF2:

"div" #>  q.groupBy(_._1).map { case (x, y) =>
  {
       ".dF1 *" #> x.name &
       ".dF2" #> y.map{ case (x2, y2) => 
           ".dF2SubDiv *" #>  y2.id
        }
  }
}

If you would rather use Slick to do the groupBy, you could find more info on it here and here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top