Filtering a deeply nested map

Hello, I am trying to filter a deeply nested map like the one below. I want to filter for the case where two of the fields match a certain condition. I’ve also included what my query currently looks like. It is wrong because it returns the same element twice.

  %Accounts.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    accounts: [
      %Accounts.Account{
        __meta__: #Ecto.Schema.Metadata<:loaded, "accounts">,
        id: 1,
        inserted_at: ~U[2020-03-13 19:55:01Z],
        account_items: [
          %AccountItem{
            __meta__: #Ecto.Schema.Metadata<:loaded, "plaid_items">,
            account_id: 1,
            id: 2,
            inserted_at: ~U[2020-03-13 19:55:03Z],
            updated_at: ~U[2020-03-13 19:55:03Z],
            user_notified_at: nil,
            notification_sent_at: nil,
            status: "sample_status_here"
          },
                   %AccountItem{
            __meta__: #Ecto.Schema.Metadata<:loaded, "plaid_items">,
            account_id: 1,
            id: 2,
            inserted_at: ~U[2020-03-13 19:55:03Z],
            updated_at: ~U[2020-03-13 19:55:03Z],
            user_notified_at: nil,
            notification_sent_at: nil,
            status: "sample_status_here"
          }
        ],
      }
    ],
    id: 1,
    inserted_at: ~U[2020-03-13 19:55:01Z],
  },
  %Accounts.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    accounts: [
      %Accounts.Account{
        __meta__: #Ecto.Schema.Metadata<:loaded, "accounts">,
        id: 1,
        inserted_at: ~U[2020-03-13 19:55:01Z],
        account_items: [
          %AccountItem{
            __meta__: #Ecto.Schema.Metadata<:loaded, "plaid_items">,
            account_id: 1,
            id: 2,
            inserted_at: ~U[2020-03-13 19:55:03Z],
            updated_at: ~U[2020-03-13 19:55:03Z],
            user_notified_at: nil,
            notification_sent_at: nil,
            status: "sample_status_here"
          },
          %AccountItem{
            __meta__: #Ecto.Schema.Metadata<:loaded, "plaid_items">,
            account_id: 1,
            id: 2,
            inserted_at: ~U[2020-03-13 19:55:03Z],
            updated_at: ~U[2020-03-13 19:55:03Z],
            user_notified_at: nil,
            notification_sent_at: nil,
            status: "sample_status_here"
          }
        ],
      }
    ],
    id: 1,
    inserted_at: ~U[2020-03-13 19:55:01Z],
  },
]

This is my current function:

   Enum.flat_map(map, fn user ->
      Enum.flat_map(user.accounts, fn account ->
        Enum.filter(
          account.account_items,
          fn item ->
            item.status == "pending" and
              item.notification_sent_at == nil
          end
        )
      end)
    end)

I expect to get all of the items that fulfill the criteria of

item.status == "pending" and
              item.notification_sent_at == nil

You left out the filter you currently have and the conditions. Also you missed to say what result you expect to get.

I haven’t actually executed this because I’d have to create struct modules to do it, but I’d be looking at something like:

for user <- list_of_users,
  account <- user.accounts,
  %{status: "pending", notification_sent_at: nil} = item <- account.account_items,
  do: item

edit: add newlines into the code because I hate how the forum software (plus Safari?) render long single line codeblocks. The scroll bar hides the content

1 Like