Home > Software engineering >  How to select columns from preloaded data and group in Ecto?
How to select columns from preloaded data and group in Ecto?

Time:12-12

I have 3 tables: sales, products, and sales_products. Sales contains information about sales made as the name implies, products contains information about various products, and sales_products is an intermediary table with a sale_id product_id composite key, and a quantity field.

My current Ecto query looks like this:

    query =
      from s in Sale,
      inner_join: sp in SaleProduct,
      on: sp.sale_id == s.id,
      inner_join: p in Product,
      on: p.id == sp.product_id,
      group_by: s.id,
      order_by: [asc: :date],
      preload: [:sale_products]

This works in that I get a result similar to:

[%Sale{
    [...],
    sale_id: ID,
    sale_products: [
      %SaleProduct { product: #Ecto.Association.NotLoaded<association :product is not loaded>, sale_id: ID, product_id: PID }
    ],
    [...]
}]

Firstly, how do I preload 'product' for SaleProduct when it is inside its own preloaded struct?

And secondly, and the main question, how do I select only specific columns from sale_products? I am trying to return this as a json Object, however I get a Poison error as it does not know how to encode some fields, and I just want to select the fields I need from the SaleProduct struct to rectify this.

CodePudding user response:

I solved this.

To preload product for SaleProduct, you just nest the preload:

preload: [..., saleproducts: [:product], ...]

And to solve the overarching question, you actually don't use preload at all, but rather fragment:

select: %{products: fragment("JSON_ARRAYAGG(JSON_OBJECT('product_id', ?, 'quantity', ?))", sp.product_id, sp.quantity)}
  • Related