Concatenating string of attributes from embedded resource array

How would one go about concatenating strings from a specific attribute on a related embedded resource?

The specific scenario is a resource called Event that has an embedded array of Attendees which in turn has a name attribute.

Event:

attribute :attendees, {:array, MyApp.MyDomainSoon.NaturalPerson}, allow_nil?: true

I started out with this just to get the data to concatenate but ran into trouble immediately.

aggregates do
  list :attendee_names, :attendees, :name
end

This error was thrown.

an exception was raised:
    ** (Spark.Error.DslError) [MyApp.MyDomainSoon.Event]
 aggregates -> attendee_names:
  relationship referenced in aggregate `MyApp.MyDomainSoon.Event.attendees` does not exist
        (ash 2.19.14) lib/ash/resource/verifiers/validate_aggregates_supported.ex:29: 

I would assume that one cannot list embedded “relationships”? I know that embedded resources themselves cannot have relationships or aggregates, but at least calculations (I did read the docs yes :innocent: hopefully well enough though).

Most grateful for any input :pray:t3:

Having such an amazing time with Ash!

So, there are two answers here, depending on what you need to be able to do with the value. One is easy and done with regular elixir, the other one is a bit more complicated but is also more flexible.

With a module calculation

defmodule AttendeeNames do
  use Ash.Calculation

  # ensure attendees is selected
  def load(_, _, _), do: [:attendees]

  def calculate(records, _, _) do
    Enum.map(records, fn record -> 
      Enum.map(record.attendees, &(&1.name))
    end)
  end
end

calculate :attendee_names, {:array, :string}, AttendeeNames

This version can be used to display a value, but it cannot be used in filters/sorts, because it cannot be lowered to the data layer.

With an expression

calculate :attendee_names, {:array, :string}, expr(fragment("ARRAY_AGG(jsonb_array_elements(?)->>'name')", attendees))

You’ll need to play with the above expression to make sure it does what you want, thats just from memory.

With this one, you’ll be able to sort and filter on this calculated value.

1 Like

Many thanks Zach!

The module calculation is actually more than enough for now. But I will be needing to solve the json aggregation fairly soon. It does indeed need a little polishing.

I’ll make sure to post my results for posterity and mark the thread as solved :slight_smile:

Thank you Zach! :pray:t3:

1 Like