用Elixir编写EXTO查询

用Elixir编写EXTO查询,elixir,phoenix-framework,ecto,Elixir,Phoenix Framework,Ecto,我已根据从客户端传入的参数列表创建了一个查询列表: [ #查询, #异位查询 ] 但是,我需要遍历这个列表并组成一个查询,它是所有查询的总和。。 (下一个查询的输入是当前查询等) 有人能给我指出正确的方向吗。非常感谢 我知道我可以一个接一个地编写查询。但是我正在从客户端获取参数,并且有一个很长的字段列表(品牌、类型等),我不想对每个字段进行单独的查询。除非打开单个查询结构并检查其底层实现,否则不可能也不建议像这样在EXTO中加入查询。相反,您应该尝试将它们分解并使其可组合 EXTO使您能够非常

我已根据从客户端传入的参数列表创建了一个查询列表:

[
#查询,
#异位查询
]
但是,我需要遍历这个列表并组成一个查询,它是所有查询的总和。。 (下一个查询的输入是当前查询等)

有人能给我指出正确的方向吗。非常感谢


我知道我可以一个接一个地编写查询。但是我正在从客户端获取参数,并且有一个很长的字段列表(品牌、类型等),我不想对每个字段进行单独的查询。

除非打开单个查询结构并检查其底层实现,否则不可能也不建议像这样在EXTO中加入查询。相反,您应该尝试将它们分解并使其可组合

EXTO使您能够非常轻松地组合查询:

defmodule视频查询做什么
导入外部查询
def带有_品牌(查询,品牌)do
其中(查询[v],v.brand==^brand)
结束
def带有_类型(查询,类型)do
其中(查询[v],v.type==^type)
结束
def最新_优先(查询)do
订购人(查询,描述::插入地点)
结束
结束
你可以这样称呼他们:

视频
|>视频查询。与_品牌(“可口可乐”)
|>VideoQueries.with_类型(“can”)
|>VideoQueries.latest_first


现在假设您获得了查询参数的
映射
关键字列表
,如果您想要应用它们,您仍然可以在运行时通过迭代键/值来调用它们。您可以构建一个过滤器方法来实现这一点:

#假设args是关键字列表或带有Atom键的映射
def过滤器(查询,参数)do
reduce(args,query,fn{k,v},query->
案例k-do
:brand->with_brand(查询,v)
:type->with_type(查询,v)
_->查询
结束
(完)
结束
并可以动态组合查询,如下所示:

user_input=%{brand:“Cocacola”,键入:“can”}
视频
|>VideoQueries.filter(用户输入)
|>全部回购


进一步阅读:

  • 博文:
  • 放映:
  • 长生不老药论坛:

尽管我同意@sheharyar的观点,即可组合查询是最好的方法,但有时我们需要超越最佳实践的解决方案。因此,我将对你的问题提供一个答案

不要让我的示例模式分散你的注意力。这只是我用来测试解决方案的一个项目

要检查查询结构,可以尝试以下操作:

iex(128)>Map.from_struct(from(OneIosThemeGen.Themes.Entry中的q,其中:q.base_hex==^base_hex))
%{
协会:[],
无,,
发件人:{“entries”,OneIosThemeGen.Themes.Entry},
组别:[],
拥有:[],
加入:[],
限额:零,
锁:零,
抵销:无,
订单号:【】,
前缀:nil,
预载:[],
选择:无,
资料来源:无,
更新:[],
其中:[
%exto.Query.BooleanExpr{
表达式:{:==,[],
[{:,[],[{:&,[],[0]},:base_hex]},[],[]},{:^,[],[0]},
文件:“iex”,
第128行,
op::和,
参数:[{E8EBED',{0,:base#u hex}]
}
]
}
如您所见,where子句保存在
where
字段中。它包含一个列表

因此,我们可以从每个查询中提取
where
字段,并连接列表。这就是我在下面演示的内容

下面是一个组合多个查询的where子句的示例。它只处理where子句,将它们加在一起

base_hex=“#E8EBED”
name=“bodyText”
查询=[
from(OneIosThemeGen.Themes.Entry中的q,其中:q.base\u hex==^base\u hex),
from(OneIOSemeGen.Themes.Entry中的q,其中:q.name==^name)
]
build=fn查询->
wheres=Enum.reduce(查询,[],fn%{wheres:wheres},acc->wheres++acc-end)
from(OneIosThemeGen.Themes.Entry中的q)
|>地图放置(:何处,何处)
结束
查询=生成。(查询)
行=全部回购(查询)
#用于结果相等断言的排序函数
sort=fn list->Enum.sort(list和&1.id list.flatte()
排序。(行3)!=排序。(行)
#真的
put(“length{rows,rows3}:”inspect({length(rows),length(rows3)}))
#长度{行,行3}:{2,5}

请注意,此解决方案依赖于Ecto查询的内部结构,这通常是一种不好的做法。它可能会在未来的Ecto更新中中断。但是,这是针对所问特定问题的一种潜在解决方案。

我想知道是否有更可接受的方法来实现这一点,因为我不希望依赖于Ecto q的结构也不要对每个查询单独进行查询。不过感谢您提供了这个聪明的解决方案!@phil可能有。您需要在列表中存储实际的查询,还是只存储列表中的键/值。类似于[brand:“Cocacola,type:“can”]?。如果是这样,那么您可以这样做:Enum.reduce(列表,来自(视频中的v)),fn{k,y},acc->where(acc,[q],field(q,^k)=^y)end)是的,我把查询存储在一个列表中,似乎用了错误的方法。你能为最后一部分提供一个例子吗?(从列表中组合)那么您想要一些动态解决方案吗?您可以使用
https://hexdocs.pm/ecto/Ecto.Query.API.html#field/2
。我将使用任何字段ad值动态生成查询。您只需使用params中的键值对对进行迭代即可。@script谢谢您。。是的,我实际上使用了Sheharyar的解决方案,并使用字段/2动态获取I而不是对每个字段进行多个查询