我对某些预紧力的顺序有疑问。
基本上,我有一个类似Restaurant > FoodItem > OptionGroup
的结构。
OptionGroup
与Restaurant
关联,并且可以与FoodItem
(具有many_to_many FoodItemOptionGroup
的表)关联。
在food_item.ex
中,我有以下内容:
many_to_many(
:option_groups,
OptionGroup,
join_through: FoodItemOptionGroup,
on_delete: :delete_all
)
我允许前端使用所需的预加载来查询API,因此它们可以执行以下操作:?include=food_item.option_groups
。该函数迭代并创建一个预加载结构。这是核心部分:
is_atom(value) ->
case value do
:food_items ->
[{:food_items, from(p in FoodItem, order_by: [p.id])}]
:option_groups ->
[{:option_groups, from(og in OptionGroup, order_by: og.id)}]
:food_extras ->
[{:food_extras, from(fe in FoodExtra, order_by: fe.id)}]
end
最近,我已经实现了一个row_weight
,它允许我按其值进行排序。在FoodItem
上很简单,只需添加order_by即可完成。在OptionGroups
上,情况很复杂。因为row_weight
在关联many_to_many FoodItemOptionGroup
上,所以预加载无法正常工作。
is_atom(value) ->
case value do
:food_items ->
[{:food_items, from(p in FoodItem, order_by: [p.row_weight, p.id])}]
:option_groups ->
[
{
:option_groups,
OptionGroup
|> join(
:inner,
[og],
fiog in Ketchup.FoodItemOptionGroup,
og.id == fiog.option_group_id
)
|> order_by([og, fiog], [fiog.row_weight, og.id])
}
]
:food_extras ->
[{:food_extras, from(fe in FoodExtra, order_by: fe.id)}]
end
这将导致多个option_groups
与它们与其他food_items
的关联数重复。预接缝只能选择正确的选项,例如Temperature
和Spice
,还可以选择其他所有的Temperature
和Spice
(它们共享相同的id
因为是其他food_items
中的一些)。
存在使用group_by
的可能解决方案,因为我认为它不会影响输出OptionGroup
。
OptionGroup
|> join(:inner, [og], fiog in Ketchup.FoodItemOptionGroup, og.id == fiog.option_group_id)
|> order_by([og, fiog], [fiog.row_weight, og.id])
|> group_by([og, fiog], [og.id, fiog.row_weight])
但是如果作为预加载运行,则会出现以下错误。如果作为标准查询运行,它确实会检索正确的OptionGroups
。
** (Postgrex.Error) ERROR 42803 (grouping_error): column "f2.id" must appear in the GROUP BY clause or be used in an aggregate function
在第一个示例中,看起来它需要food_item_id
进行过滤,但是唯一的方法是使用function in preload。
fn food_items_ids ->
OptionGroup
|> join(:inner, [og], fiog in Ketchup.FoodItemOptionGroup,
og.id == fiog.option_group_id and fiog.food_item_id in ^food_items_ids)
|> order_by([og, fiog], [fiog.row_weight, og.id])
|> Ketchup.Repo.all()
end
但是在这种情况下,预加载将仅添加与OptionGroup
具有相同id
的{{1}}。
我想我在这里没有选择的余地,我在想一个可能没有选择要选择的预加载的选项的正确查询。
编辑
这是我要发送给Ecto的预载:
FoodItem
GET ../endpoint1?include=option_groups
我在这里显示的内容没有区别,但是区别在于它将显示所有OptionGroup,但不会排序它们,因为row_weight在所有它们中均不可用,当我只想要一个与{{1 }}具有[
option_groups: #Ecto.Query<from o in Ketchup.OptionGroup,
join: f in Ketchup.FoodItemOptionGroup, on: o.id == f.option_group_id,
order_by: [asc: f.row_weight, asc: o.id]>
]
。
FoodItem
row_weight
EDIT2
因此,我最终使用了查询。将来我将尝试实现GraphQL。
GET ../endpoint2?include=food_items.option_groups.food_extras