Elixir - 使用 table 关联进行排序
Elixir - Order by using table associations
我正在尝试执行查询以获取 user_posts
table 和相应的关联 upvotes
、downvotes
和 comments
。我试过这样:
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
时,我更喜欢使用 join
和 on
,这样我就不会混淆 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
.
现在,如果您仍然有问题,请开始直接从数据库中一个接一个地删除您的连接,看看有什么问题。
我的建议:
- 从查询中删除所有
join
和 Schema
- 关注: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)))
它按预期工作。
我正在尝试执行查询以获取 user_posts
table 和相应的关联 upvotes
、downvotes
和 comments
。我试过这样:
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
时,我更喜欢使用 join
和 on
,这样我就不会混淆 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
.
现在,如果您仍然有问题,请开始直接从数据库中一个接一个地删除您的连接,看看有什么问题。
我的建议:
- 从查询中删除所有
join
和Schema
- 关注: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)))
它按预期工作。