Search code examples
elixirecto

Protocol Ecto.Queryable not implemented for Item of type List


Background

I have an List of metadata items that has the following format:

[%{id: "id1"}, %{id: "id2"}, %{id: "id3"}] 

I am trying to do a query using a join with this list, the idea here is to pick posts who have this specific metadata ids.

relevant_metadata_ids = [%{id: "id1"}, %{id: "id2"}, %{id: "id3"}] 

posts =
      Post
      |> join(:inner, [post], meta in ^relevant_metadata_ids,
        on: fragment("?->>'meta_id'", post.metadata) == meta.id
      )

Problem

However, it seems I can't quite do this, as I get the following error:

** (Protocol.UndefinedError) protocol Ecto.Queryable not implemented for [%{meta_upload_id: "id1"}] of type List. This protocol is implemented for the following type(s): Atom, BitString, Ecto.Query, Ecto.SubQuery, Tuple

Question

Is there a way to leverage the information I have in the list and use it in an Ecto Query?


Solution

  • Solution

    I have found a way around my problem. If using join is not a viable option, then perhaps I can use another construct. This is the case for where.

    By changing the list List of metadata items to just the ids:

    [%{id: "id1"}, %{id: "id2"}, %{id: "id3"}] 
    # becomes
    ["id1", "id2", "id3"]
    

    I can then transform my query to use a where clause:

    relevant_metadata_ids = ["id1", "id2", "id3"]
    
    posts =
          Post
          |> where([post], fragment("?->>'meta_id'", post.metadata) in ^relevant_metadata_ids)
          |> ...
    

    This works as it seems to be quite fast. If the ids inside of relevant_metadata_ids are not repeated, its even better.

    I will eventually have to join with a correspondent table though, but this does the job.