Skip to content
This repository has been archived by the owner on Nov 18, 2020. It is now read-only.

Missing query results with many_to_many mapping with Join schema #40

Open
anandtrex opened this issue Aug 15, 2017 · 1 comment
Open

Comments

@anandtrex
Copy link

Issue

If I have two schemas that are related through a many_to_many relationship using a Join schema, I do not get the expected number of results (I get too few values) when I query the database with rethinkdb_ecto to retrieve all items associated with one item of the other schema.
I have verified that the join schema table itself contains the right data, and queries to rethinkdb directly using eqJoin give the expected number of results.

I'm using phoenix 1.3.0, elixir 1.5.1, erlang/OTP 20 on Archlinux with rethinkdb 2.3.6.

Detailed steps to reproduce

I have two schemas like so:

defmodule TestRethink.Post do
  use Ecto.Schema
  import Ecto.Changeset
  alias TestRethink.Post

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "posts" do
    field :content, :string
    field :title, :string
    many_to_many :tags, TestRethink.Tag, join_through: TestRethink.PostTag, on_delete: :delete_all
    timestamps()
  end

  @doc false
  def changeset(%Post{} = post, attrs) do
    post
    |> cast(attrs, [:title, :content])
    |> validate_required([:title, :content])
  end
end

defmodule TestRethink.Tag do
  use Ecto.Schema
  import Ecto.Changeset
  alias TestRethink.Tag

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "tags" do
    field :name, :string
    many_to_many :posts, TestRethink.Post, join_through: TestRethink.PostTag, on_delete: :delete_all
    timestamps()
  end

  @doc false
  def changeset(%Tag{} = tag, attrs) do
    tag
    |> cast(attrs, [:name])
    |> validate_required([:name])
  end
end

which have a many-to-many mapping between each other using an intermediate schema (like in the official example:

defmodule TestRethink.PostTag do
  use Ecto.Schema
  import Ecto.Changeset
  alias TestRethink.PostTag

  @primary_key false
  @foreign_key_type :binary_id
  schema "posts_tags" do
    belongs_to :post, Post
    belongs_to :tag, Tag
    timestamps()
  end

  @doc false
  def changeset(%PostTag{} = post_tag, attrs) do
    post_tag
    |> cast(attrs, [:post_id, :tag_id])
    |> validate_required([:post_id, :tag_id])
  end
end

Now I put 150 items in :posts, all of which are associated with, say, one item in :tags like so:

# Insert 150 Posts
posts = 1..150  |> Enum.map(fn _ -> 
  Post.changeset(%Post{}, %{title: "Some Title", content: "This is a sentence"}) 
  |> Repo.insert! 
end)

# Insert 1 tag
tag = Tag.changeset(%Tag{}, %{name: "Shakespeare"}) |> Repo.insert!

# Insert associations between all the posts and the one tag
Enum.map(posts, 
         fn post -> PostTag.changeset(%PostTag{}, %{post_id: post.id, tag_id: tag.id})
         |> Repo.insert! 
         end)

Now, when I try to retrieve all the posts associated with the tag:

tag = hd Repo.all(Tag)
posts = Repo.all(assoc(tag, :posts))

I do not get back 150 posts as expected, but much fewer. In fact the exact number of posts I get back varies from time to time, and is around 40-50.

@redrabbit
Copy link
Member

redrabbit commented Nov 4, 2017

I did investigate a little bit on this and found out that many_to_many require more complex handling of joins via the adapter. Don't have time to fix this right now but any help is welcome.

In the meantime, you might want to stick to has_many or embeds_many.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants