Ecto:通过URL参数的多个过滤器

总览

昨天,在使用RESTful API时 ,我遇到了一个棘手的问题。

如何根据URL中传递的参数过滤Ecto结果?

在这个迷你教程中,我们将构建一个可重用的模块来处理过滤。

情况

我们构建了一个API端点来获取所有用户的待办事项。 该todos表有一个state栏和每个待办事项项目可以有状态donedoingpending

我们正在努力实现的目标

我们希望基于请求URL的参数过滤查询结果。 例如,当用户调用此端点时,我们仅应包括具有doing或`done`状态的待办事项:

https:// my-awesome-api.io/v1/todos?filter[state]=doing,done
样板

通常,要获取所有用户的待办事项,我们在上下文文件中包含以下内容:

Todos上下文样板

我们在控制器中这样调用此函数:

Todos控制器样板

由于过滤器参数将在URL中传递,因此我们需要将params变量传递给上下文的list_todos/2函数。 我们需要这样修改控制器:

通过这样做,我们还需要在上下文中调整list_todos函数的list_todos 。 现在,我们还将使用稍后将要构建的filter模块来准备上下文。

注意 :FilterEx是我们稍后将构建的模块的名称。

第7行中 ,我们只是检查filter参数是否存在。 如果存在,则以列表形式返回过滤器参数 ,如果不存在,则仅返回一个空列表。

现在,我们将构建FilterEx模块来处理过滤。

构建FilterEx模块

在构建此模块时,我们将利用Ecto.Query.dynamic / 2 。 如果您想了解更多信息,请参阅官方文档 。 基本上, Ecto.Query.dynamic/2让我们一点一点地构建查询表达式,并稍后在主查询中进行插值。

“…稍后在我们的主要查询中插值

您可能想知道为什么我们不像这样在上下文中添加对FilterEx的调用: where([t], t.user_id == ^user.id and ^FilterEx.filter(states, :state))

不过有一个陷阱。

dynamic可在的根被内插wherehavingjoinon

这就是为什么我们在第一个where子句之后添加了FilterEx调用,而不仅仅是对其进行插值的原因。 必须在子句的根部进行插值。

现在让我们定义模块并导入必要的Ecto模块。

defmodule FilterEx do
import Ecto.Query
  # ...
end

FilterEx.filter/3期望第一个参数为工作查询,第二个参数为过滤器列表,第三个参数为列名。

defmodule FilterEx do
import Ecto.Query
  @spec filter(Ecto.Query.t, list, atom) :: Ecto.Query.t  
def filter(query, [head | tail], fieldname) do
...
end
  def filter(query, [], _), do: query
end

filter/3函数内部,我们将构建我们的初始动态查询,该查询将传递给filter_field/3函数以进行进一步的动态查询构建。 然后,我们将dynamic_query插入到主查询中,并将其返回到管道中。

...
  def filter(query, [head | tail], fieldname) do
dynamic_query =
dynamic([q], field(q, ^fieldname) == ^head)
|> filter_field(tail, field_name)
    query |> where(^dynamic_query) 
end
...

我们将在filter_field/3函数中使用递归方法。

...
  def filter_field(dynamic, [head | tail], fieldname) do
dynamic([q], field(q, ^fieldname) == ^head or ^dynamic)
|> filter_field(tail, fieldname)
end
...

现在,我们已经完成了FilterEx模块的构建。

这是完成的版本:

感谢您的阅读。 如有任何疑问,您随时可以在Twitter @VinceUrag上与我联系

学到一些有价值的东西? 你总可以给我买杯咖啡 。 ❤

在Github上与我联系:

From: https://hackernoon.com/ecto-multiple-filters-via-url-parameters-fd0e4a8b5074

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值