elixir - Ecto 对嵌套关联的限制

标签 elixir phoenix-framework ecto

我在使用 Ecto 进行查询时遇到一些问题:

SavedDevice
    - belongs_to Devices
    - belongs_to User
Device
    - has_many SavedDevices
    - has_many DeviceLocations
DeviceLocation
    - belongs_to Devices

我想要加载属于用户SavedDevices,并保存最新的DeviceLocation

这个解决方案工作正常:

  def list_pdevices_locations(user, limit \\ 0) do
    location_query = from(dl in DeviceLocation, order_by: [desc: :inserted_at])
    query =
      from(d in ProvisionedDevice,
        preload: [device_info: [locations: ^location_query]],
        limit: ^limit
      )

    if user.is_admin do
      Repo.all(query)
    else
      Repo.all(from(d in query, where: d.user_id == ^user.id))
    end
  end

但它会加载每个DeviceLocations。这是一个问题,因为可能有数千个,而我只需要最后一个。

当我将 limit: 1 添加到 location_query 时,它只为所有设备返回 1 个DeviceLocation,并且不是 1 个设备位置设备

有什么想法吗?

最佳答案

我不知道这是否可以在预加载中完成,但您可以使用 lateral joins (第 7.2.1.5 节)以实现您想要的目标。您将需要为位置创建子查询:

location_query =
  from(dl in DeviceLocation,
    where: parent_as(:d_info).id == dl.device_info_id,
    # Unique rows by device_info_id
    distinct: dl.device_info_id,
    # Order by inserted at to get the most recent entry
    order_by: [desc: dl.inserted_at]
  )

然后从 ProvisionedDevice 加入它:

query = 
  from(pd in ProvisionedDevice,
    inner_join: di as assoc(pd, :device_info),
    # Use the same alias as specified in the subquery
    as: :d_info,
    inner_lateral_join: dl in subquery(location_query),
    on: dl.device_info_id == di.id,
    # You can structure this select any way you like
    select: %{device: pd, info: di, location: dl}
  )

当然,这将不再符合您示例中的返回规范,但您可以对结果进行后期处理以符合您之前的契约(Contract)(如果需要):

for %{device: device, info: info, location: location} <- Repo.all(query) do
  info_and_location = %{info | locations: [location]}
  %{device | device_info: info_and_location}
end

无论哪种方式,查询都会在一个查询中为您提供一台设备及其信息和最近位置。

关于elixir - Ecto 对嵌套关联的限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69100027/

相关文章:

config - EXRM - 我可以从 config.exs 文件设置 vm.args 值吗?

elixir - => 和 : in an Elixir map? 有什么区别

测试 Elixir/Phoenix 服务模块

elixir - Ecto build_assoc/3 与定义的外键不匹配?

elixir - 为 Mix 任务启动 Ecto(Mix.EctoSQL.ensure_started 不再工作)

elixir - 使用带有子查询的 Ecto 进行预加载并使用主查询中的联接

elixir - 如何获得列表的排列?

elixir - Phoenix Web 框架中的 KeyError

postgresql - 你如何使用 Ecto 按时间对带有日期时间的表格进行排序?

postgresql - (Postgrex.Error) 错误 58P01 (undefined_file)