Elixir - 使用 table 关联进行排序

Elixir - Order by using table associations

我正在尝试执行查询以获取 user_posts table 和相应的关联 upvotesdownvotescomments。我试过这样:

popular_posts =
  from(s in UserPost, 
    where: s.inserted_at >= ^Timex.beginning_of_month(Timex.now()),
    where: s.inserted_at <= ^Timex.end_of_month(Timex.now()),
    left_join: downvotes in assoc(s, :downvotes),
    left_join: comments in assoc(s, :comments), 
    left_join: upvotes in assoc(s, :upvotes),
    preload: [comments: comments, upvotes: upvotes, downvotes: downvotes],
    order_by: fragment("(? * 0.5) + (? * 0.1) - (? * 0.4)", ^map_size(s.upvotes), ^map_size(s.comments), ^map_size(s.downvotes)))
  |> Repo.all

但它给出了以下警告和错误:

warning: variable "s" does not exist and is being expanded to "s()", please use parentheses to remove the ambiguity or change the variable name
  lib/nethub_api_web/resolvers/content.ex:33

warning: variable "s" does not exist and is being expanded to "s()", please use parentheses to remove the ambiguity or change the variable name
  lib/nethub_api_web/resolvers/content.ex:33

warning: variable "args" is unused
  lib/nethub_api_web/resolvers/content.ex:93


== Compilation error in file lib/nethub_api_web/resolvers/content.ex ==
** (CompileError) lib/nethub_api_web/resolvers/content.ex:33: undefined function s/0
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

我尝试将 s 更改为 UserPosts,但它说 table 中不存在这些列。

这可能有帮助:

on

left_join 转换为 join

这是来自 Ecto 文档的示例:

 from c in Comment,
  join: p in Post, on: p.id == c.post_id,
  select: {p.title, c.text}

参考: https://hexdocs.pm/ecto/Ecto.Query.html#join/5

当我有很多 join 时,我更喜欢使用 joinon,这样我就不会混淆 Ecto。

同时将 where 移到 join 之后,这不是很重要,但是 RDBMS 中的一句老话。在 Where 之前加入。

在您的 Where 子句中,使用 and 而不是第二个 where。 (再一次更好地做到这一点 Ecto.Query 因为你不会把事情分成几部分。


现在,如果上述 none 解决了您的问题,则绕过 Schema 并将 UserPost 替换为 "user_posts" 并手动构建所有连接。然后 使用 Ecto.Adapters.SQL.to_sql(:all, Repo, query) 其中 query 是你的 from 结果然后 运行 直接在你的数据库上生成 SQL 并检查那里的错误,你可以在那里调整你的查询和将其翻译回 Ecto.


现在,如果您仍然有问题,请开始直接从数据库中一个接一个地删除您的连接,看看有什么问题。


我的建议:

  • 从查询中删除所有 joinSchema
  • 关注:https://hexdocs.pm/ecto/Ecto.Query.html#join/5
  • 写一个 Raw sql 并忽略 Ecto
  • 运行 你的 SQL 直接在 DB OR
  • 运行 SQL 直接用 Ecto.Adapters.SQL.query(Repo, query, [params1, params2])
  • 然后翻译成Ecto

我仍然不知道为什么,但是当我改变时:

preload: [comments: comments, upvotes: upvotes, downvotes: downvotes],
order_by: fragment("(? * 0.5) + (? * 0.1) - (? * 0.4)", 
^map_size(s.upvotes), ^map_size(s.comments), ^map_size(s.downvotes)))

至:

preload: [:comments, :upvotes, :downvotes],
order_by: fragment("(? * 0.5) + (? * 0.1) - (? * 0.4)", 
^map_size(:upvotes), ^map_size(:comments), ^map_size(:downvotes)))

它按预期工作。