# Ash: 8 - Aggregates ```elixir Application.put_env(:ash, :validate_domain_resource_inclusion?, false) Application.put_env(:ash, :validate_domain_config_inclusion?, false) Mix.install([{:ash, "~> 3.0"}], consolidate_protocols: false) ``` ## Aggregates
Code Interfaces
Home
Calculations
### In this tutorial you will add an Aggregate on a Resource [Aggregates](https://hexdocs.pm/ash/aggregates.html) in Ash allow for retrieving summary information over groups of related data. Aggregates can be either _count_, _first_, _sum_ or _list_. Implement a count aggregate on the 'open tickets' a representative is assigned to. First explore the comments in the code below, to make this work properly you have to add the inverse relationship of belongs_to inside the Representative resource. To add an aggregate define an `aggregates do .. end` block inside the representative. Inside the `aggregates` block, define a `count :count_of_open_tickets, :tickets do .. end` block. Then inside this block, define a filter like so: `filter expr(status == :open)` Also, notice what happens when you don't define a filter.
Show Solution
```elixir aggregates do count :count_of_open_tickets, :tickets do filter expr(status == :open) end end ```
### Enter your solution ```elixir defmodule Tutorial.Support.Ticket do use Ash.Resource, domain: Tutorial.Support, data_layer: Ash.DataLayer.Ets actions do defaults [:read] # On creation set the representative by providing the id create :open do accept [:subject, :description, :representative_id] end update :close do accept [] change set_attribute(:status, :closed) end update :assign do accept [:representative_id] end end attributes do uuid_primary_key(:id) attribute :subject, :string, allow_nil?: false attribute :description, :string, allow_nil?: true attribute :status, :atom do constraints one_of: [:open, :closed] default :open allow_nil? false end create_timestamp :created_at update_timestamp :updated_at end relationships do belongs_to :representative, Tutorial.Support.Representative end code_interface do define :assign, args: [:representative_id] # <- added representative_id define :open, args: [:subject, :description, :representative_id] define :close, args: [] end end defmodule Tutorial.Support.Representative do use Ash.Resource, domain: Tutorial.Support, data_layer: Ash.DataLayer.Ets actions do defaults [:read] create :create do accept [:name] end end attributes do uuid_primary_key :id attribute :name, :string end # Added the inverse relationship of belongs_to in the ticket. # This way we can reference :tickets inside the aggregates. relationships do has_many :tickets, Tutorial.Support.Ticket end code_interface do define :create, args: [:name] end # <- Add the aggregates here end ``` ```elixir defmodule Tutorial.Support do use Ash.Domain resources do resource Tutorial.Support.Ticket resource Tutorial.Support.Representative end end ``` ## Query the Aggregate Use a [Bulk Create](https://hexdocs.pm/ash/create-actions.html#bulk-creates) to create 4 tickets, 3 of which are assigned to Joe. ```elixir # Create a representative joe = Tutorial.Support.Representative.create!("Joe Armstrong") # Bulk create 4 tickets, 3 of which are assigned to Joe [ %{subject: "I can't see my eyes!"}, %{subject: "I can't find my hand!", representative_id: joe.id}, %{subject: "My fridge is flying away!", representative_id: joe.id}, %{subject: "My bed is invisible!", representative_id: joe.id} ] |> Ash.bulk_create(Tutorial.Support.Ticket, :open, return_records?: true) ``` Close the last ticket assigned to Joe. ```elixir require Ash.Query # Retrieve the last ticket [last_ticket] = Tutorial.Support.Ticket |> Ash.Query.filter(representative_id == ^joe.id) |> Ash.Query.sort(created_at: :desc) |> Ash.Query.limit(1) |> Ash.read!() # Close the last ticket Tutorial.Support.Ticket.close!(last_ticket) ``` ```elixir joe = Ash.load!(joe, [:count_of_open_tickets]) joe.count_of_open_tickets ``` The result should be __2__, as you opened 4 tickets, 3 were assigned to Joe, but the last assigned ticket was closed.
Code Interfaces
Home
Calculations