If I have relations like this:
blogs has_many posts
posts many_to_many users
blogs many_to_many users
How can I limit loading posts of users to only one blog?
blog (id 80) → users → posts of blog (id 80)
By default it loads all posts of users in every blog.
blog (id 80) → users → posts of all blogs
In Ecto, I can do this
Repo.get!(Blog, 80)
|> Repo.preload([
users: [posts: from(p in Post, where: p.blog_id == 80)]
])
Api.get!(Blog, 80)
|> Api.load(users: [posts: Ash.Query.filter(blog_id == ^80)])
1 Like
Can I use Ash.Query.filter
for loading relationships in ash_graphql
or ash_json_api
declaratively?
listBlogs {
id
users {
id
posts {
id # posts in grandparent blog only?
}
}
If I load a list of Blogs with a custom read action, how would I pass the blog_id to filter posts?
read :list_blog_user_post do
prepare build(load: [
users: [
posts: Ash.Query.filter(blog_id == ^blog_id) # ???
]
])
end
There is not really a good way to accomplish this if I’m being honest. It’s not a pattern that would be easily generalizable to support all of the relationship features that Ash has. You’d potentially be able to accomplish this with a calculation on the parent object (blog) that produces a list of users and for each their posts in the parent blog. I.e
defmodule YourApp.Types.UserWithPosts do
use Ash.Resource, data_layer: :embedded
attributes do
attribute :user, :struct do
constraints [instance_of: User]
allow_nil? false
end
attribute :posts, {:array, :struct} do
constraints [items: [instance_of: Post]]
allow_nil? false
end
end
end
# in blog
calculate :users_and_posts, {:array, YourApp.Types.UserWithPosts}, YourCalculation
Where YourCalculation
is a module that produces a list of those embedded types.
1 Like