Using Ecto preload to load relationships in one query

Hello! Loving using Ash so far. I'm trying to make a simple Reddit clone, and I have a structure basically like this: - Post - belongs to an author (user) - belongs to a community When I display a post, I need to fetch the author and the community (so I can link to both). Currently I'm doing this by just building a load into my action:
read :for_display do
argument :id, :string, allow_nil?: false
get? true

filter expr(id == ^arg(:id))

prepare build(load: [:author, :community])
end
read :for_display do
argument :id, :string, allow_nil?: false
get? true

filter expr(id == ^arg(:id))

prepare build(load: [:author, :community])
end
However, this does not do a join, but instead does two separate queries (one for the author, one for the community):
[debug] QUERY OK source="posts" db=0.4ms idle=464.5ms
SELECT p0."id", p0."inserted_at", p0."updated_at", p0."title", p0."body", p0."removed", p0."locked", p0."nswf", p0."author_id", p0."community_id" FROM "posts" AS p0 WHERE (p0."id"::uuid = $1::uuid) ["f5862f1b-2693-4ce2-95f9-95d07bab91da"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
[debug] QUERY OK source="users" db=0.1ms queue=0.1ms idle=419.7ms
SELECT u0."id", u0."inserted_at", u0."updated_at", u0."email", u0."hashed_password" FROM "users" AS u0 WHERE (u0."id"::uuid = $1::uuid) ["949237b2-da56-453b-a0a0-1ab7bffc70f6"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
[debug] QUERY OK source="communities" db=0.3ms queue=0.1ms idle=467.6ms
SELECT c0."id", c0."inserted_at", c0."updated_at", c0."name", c0."title", c0."description", c0."nsfw" FROM "communities" AS c0 WHERE (c0."id"::uuid = $1::uuid) ["1b6b2517-8eb4-437a-a612-a065ccf109ca"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
[debug] QUERY OK source="posts" db=0.4ms idle=464.5ms
SELECT p0."id", p0."inserted_at", p0."updated_at", p0."title", p0."body", p0."removed", p0."locked", p0."nswf", p0."author_id", p0."community_id" FROM "posts" AS p0 WHERE (p0."id"::uuid = $1::uuid) ["f5862f1b-2693-4ce2-95f9-95d07bab91da"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
[debug] QUERY OK source="users" db=0.1ms queue=0.1ms idle=419.7ms
SELECT u0."id", u0."inserted_at", u0."updated_at", u0."email", u0."hashed_password" FROM "users" AS u0 WHERE (u0."id"::uuid = $1::uuid) ["949237b2-da56-453b-a0a0-1ab7bffc70f6"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
[debug] QUERY OK source="communities" db=0.3ms queue=0.1ms idle=467.6ms
SELECT c0."id", c0."inserted_at", c0."updated_at", c0."name", c0."title", c0."description", c0."nsfw" FROM "communities" AS c0 WHERE (c0."id"::uuid = $1::uuid) ["1b6b2517-8eb4-437a-a612-a065ccf109ca"]
↳ AshPostgres.DataLayer.run_query/2, at: lib/data_layer.ex:628
How do I modify this to fetch everything in a single query? When I get into fetching nested comments in a bit, having to fetch the users and the counts in separate queries feels like it would get slow. Is there a way I can use Ecto's preload option in Ash?
1 Reply
ZachDaniel
ZachDaniel2y ago
Nothing in ash will actually fetch them in a single query. Joined queries producing multiple result sets don’t compose well with other features in Ash and also generally don’t scale as well typically. If you really want to, you can write manual actions, or use the modify_query option on read actions to alter the ecto query.

Did you find this page helpful?