【问题标题】:Ecto query retrieve all posts along with the most recent commentEcto 查询检索所有帖子以及最近的评论
【发布时间】:2021-03-17 09:27:07
【问题描述】:

注意:我使用的是 MySQL 5.7。

我有两个名为 Post、Comment 的表

  schema "posts" do
    field: id, string
    field :title, :string
    field :slug, :string
    field :active, :boolean, default: true
    timestamps()
  end

  schema "comments" do
    field: id, string
    field: post_id, string
    field :title, :string
    field :body, :string
    field :email, :string
    field :meta, :map
    field :active, :boolean, default: false
    timestamps()
  end

我使用Ecto 进行Elixir 中的数据库查询。目前,我正在尝试获取数据库中的所有帖子,以及这些帖子的最新评论(如果有)。例如:

Post 1 ──── post1__last_comment_id 
         
Post 2 ──── post2__last_comment_id      

Post 3 ──── nil

我已经在post.id == comment.id 上尝试了join_left,但它返回了与该帖子相关的所有cmets,而不仅仅是最新的。

我也尝试了grouping_by comment.post_id 并获得了最大id,虽然这有效,但这不是所需的解决方案,因为它需要基于date 而不是id 的评论。

我查找了如何做到这一点,虽然我发现很少有原始 SQL 查询的解决方案,但我找不到任何与 Ecto 类似的东西,也无法弄清楚如何将它从 SQL 转换为 Ecto。

是否可以使用 Ecto 完成?

【问题讨论】:

    标签: mysql sql elixir ecto


    【解决方案1】:

    您可以为此使用横向连接,Ecto 支持这一点。

    在处理您的用例的 Ecto 文档中有一个示例。看这里https://hexdocs.pm/ecto/Ecto.Query.html#preload/3

    以下是文档中根据您的需要调整的示例。

    Repo.all from p in Post, as: :post,
               join: c in assoc(p, :comments),
               inner_lateral_join: latest in subquery(
                 from Comment,
                 where: [post_id: parent_as(:post).id],
                 order_by: [{desc: :inserted_at}],
                 limit: 1,
                 select: [:id]
               ), on: latest.id == c.id,
               preload: [comments: c]
    

    【讨论】:

    • 我尝试了建议的解决方案,但我收到了这个 MySQL 错误:` **(Ecto.QueryError) join ':inner_lateral' 在查询中不受 MySQL 支持。`
    • 是的,MySQL 不支持横向连接。您应该查看窗口函数,这些由 MySQL afaik 支持。他们可以给你同样的结果。
    • 执行此操作后,我收到以下错误:** (MyXQL.Error) (1064) (ER_PARSE_ERROR) 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的“(PARTITION BY post_id ORDER BY start_date DESC)AS row_numberFROMcomment”附近使用正确的语法我查找了可能导致此错误的原因,我相信它可能必须使用 MySQL 版本为 5.7(不支持窗口函数)。如果是这种情况,我还有什么其他方法可以在不更新 MySQL 版本的情况下解决这个问题。
    【解决方案2】:

    distinct 应该用于此目的:

    last_comment = from c in Comments, order_by: [desc: c.id], distinct: c.posts_id
    
    q = from p in Posts,
      preload: [comments: ^last_comment]
    
    Repo.all(q) 
    |> IO.inspect
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多