预加载和排序 has_many 时的不良行为:通过关联
Undesired behavior when preloading and ordering a has_many :through association
如果我们有 3 个模式:聊天室、用户和消息
ChatRoom.ex
schema "chat_rooms" do
has_many(:users, User)
has_many(:messages, through: [:users, :messages])
end
Ecto 是否有一个既定的方法来“获取聊天室,并且关联用户的所有消息都按消息上的某个字段排序”?
我最初只是想简单地获得一个聊天室,preload
它的所有消息都按 message.inserted_at
排序,并且可以在两个查询中做到这一点(并了解如何在结合 join
和 preload
) 的单个查询中执行此操作,但是当需要按 has_many 上的值排序时:through 资源,它似乎将相同的排序应用于中间关联(在此示例中为用户)。
示例问题:因此,如果聊天室 A 中有两个用户(用户 1 第一个加入,用户 2 第二个加入),并且我们的消息序列为:
- 用户 1:“嗨”
- 用户 2:“你好”
- 用户 1:“再见”
- 用户 2:“再见”
如果我这样做了:
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 的“再见”
- user2 的“你好”
- 用户2的“告别”
这显然不是目标。您如何在 Ecto 中对预加载的查询进行排序而不将其应用于连接资源?
好吧,我不确定为什么我会发现这一天如此令人困惑,脑子放屁。显式加入这两个关联然后预加载那些现有的连接对我来说是这样的:
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
如果我们有 3 个模式:聊天室、用户和消息
ChatRoom.ex
schema "chat_rooms" do
has_many(:users, User)
has_many(:messages, through: [:users, :messages])
end
Ecto 是否有一个既定的方法来“获取聊天室,并且关联用户的所有消息都按消息上的某个字段排序”?
我最初只是想简单地获得一个聊天室,preload
它的所有消息都按 message.inserted_at
排序,并且可以在两个查询中做到这一点(并了解如何在结合 join
和 preload
) 的单个查询中执行此操作,但是当需要按 has_many 上的值排序时:through 资源,它似乎将相同的排序应用于中间关联(在此示例中为用户)。
示例问题:因此,如果聊天室 A 中有两个用户(用户 1 第一个加入,用户 2 第二个加入),并且我们的消息序列为:
- 用户 1:“嗨”
- 用户 2:“你好”
- 用户 1:“再见”
- 用户 2:“再见”
如果我这样做了:
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 的“再见”
- user2 的“你好”
- 用户2的“告别”
这显然不是目标。您如何在 Ecto 中对预加载的查询进行排序而不将其应用于连接资源?
好吧,我不确定为什么我会发现这一天如此令人困惑,脑子放屁。显式加入这两个关联然后预加载那些现有的连接对我来说是这样的:
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