1

My blog app has a Post model that has many Comments.

schema "post" do
  field :title, :string
  field :content, :string

  belongs_to :owner, MyApp.Accounts.User, foreign_key: :owner_id

  has_many :comments, MyApp.Content.Comment, foreign_key: :post_id

  timestamps()
end

I have an associated absinthe object as well.

object :post do
  field :id, :integer
  field :title, :string
  field :content, :string
  field :owner, :user, resolve: assoc(:owner)
  field :comments, list_of(:comment), resolve: assoc(:comments)
end

Queries work as expected.

Now I want to add a boolean active field to the Comments schema so that I can perform soft deletes; I'll only select comments where active == true, and I will delete comments by setting active to false.

I add the field into my schema:

field :active, :boolean, default: true, null: false

Now I only want the absinthe :comments field to return active comments. I have a custom resolver for this...

field :comments, list_of(:comment), resolve: fn (query,_,resolution) ->
  query =
    from c in MyApp.Content.Comment,
      where: c.post_id == ^query.id,
      where: c.active == true,
      select: c

  {:ok, MyApp.Repo.all(query)}
end

I'm worried this is going to run into an N+1 problem though. Is there a more elegant way to do this?

Mark Karavan
  • 2,654
  • 1
  • 18
  • 38

1 Answers1

3

You need to use a Batch Resolver here. The documentation explains everything in detail. Your query should look like the following:

query =
  from c in MyApp.Content.Comment,
    where: c.post_id in ^post_ids,
    where: c.active == true,
    select: c

{:ok, query |> MyApp.Repo.all() |> Enum.group_by(& &1.post_id)}
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
Dogbert
  • 212,659
  • 41
  • 396
  • 397