【问题标题】:Undesired behavior when preloading and ordering a has_many :through association预加载和订购 has_many 时的不良行为:通过关联
【发布时间】:2021-03-06 19:35:27
【问题描述】:

如果我们有 3 个模式:ChatRoom、User 和 Message

ChatRoom.ex
schema "chat_rooms" do
  has_many(:users, User)
  has_many(:messages, through: [:users, :messages])
end

Ecto 是否有既定的方式来“获取一个聊天室,以及关联用户的所有消息都按消息上的某个字段排序”?

我最初只是想简单地获得一个聊天室和preload 它,它的所有消息都按message.inserted_at 排序,并且可以在两个查询中执行此操作(并了解如何在单个查询中执行此操作结合 joinpreload),但是当需要按 has_many :through 资源上的值排序时,它似乎将相同的排序应用于中间关联(在本例中为用户)。

示例问题:因此,如果聊天室 A 中有两个用户(user1 首先加入,user2 第二加入),我们的消息序列为:

  • user1:“嗨”
  • user2:“你好”
  • user1:“再见”
  • user2:“再见”

如果我这样做了:

sorted_message_query = from(message in Message, order_by: message.inserted_at)

from(chat_room in ChatRoom,
  where: chat_room.id == ^chat_room_id,
  preload: [messages: ^sorted_message_query]
)

chat_room 上的 messages 结果实际上会像这样列出:

  1. user1 的“嗨”
  2. user1 的“再见”
  3. user2 的“你好”
  4. user2 的“告别”

这显然不是目标。如何在 Ecto 中对预加载的查询进行排序而不将其应用于连接资源?

【问题讨论】:

  • 我可以通过加入 chat_rooms 与用户和消息,然后通过 messages.inserted_at 订购并选择我想要的(来自 chat_rooms 和所有消息等的几个属性)来解决这个问题,但我主要是想知道预加载绑定魔法等是否有更“Ecto-y”的方式
  • 我确认 Ecto 正在将排序预加载查询应用于消息表上的 user_id 以及所需的 insert_at,这绝对是导致这种不良行为的原因,想知道 Jose 或其他人是否可以解释原因SELECT m0."id", m0."content", m0."user_id", m0."inserted_at", m0."updated_at", m0."user_id" FROM "messages" AS m0 WHERE (m0."user_id" = ANY($1)) ORDER BY m0."user_id", m0."inserted_at" [[<<...>>, <<...>>]]

标签: elixir phoenix-framework ecto


【解决方案1】:

好吧,我不知道为什么我会觉得这一天如此令人困惑,完全是在放屁。显式加入这两个关联,然后预加载那些现有的连接对我来说是这样的:

  from chat_room in ChatRoom,
    where: chat_room.id == ^chat_room_id,
    join: user in assoc(chat_room, :users),
    left_join: message in assoc(user, :messages),
    preload: [users: user, messages: message],
    order_by: message.inserted_at

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多