【问题标题】:Phoenix/Ecto: List all posts, include 3 latest comments’ titlePhoenix/Ecto:列出所有帖子,包括 3 条最新评论的标题
【发布时间】:2017-03-22 16:20:22
【问题描述】:

我有一个 Post 架构,其中包含多个评论。我想在一页上列出所有带有 cmets 的帖子(我将单独使用分页),使用单个数据库查询,具有以下限制:

首先:我想将每个帖子的预加载限制为 3 个最新的 cmets(不是全部,因为可能有数百个)。

第二:我只想从评论中预加载标题列,并避免使用“文本”列,因为文本可能包含太多内容。

我的最终结果是:

Post 1 ──┬── Comment 1 Title
         │── Comment 2 Title
         └── Comment 3 Title

Post 2 ──┬── Comment 1 Title
         │── Comment 2 Title
         └── Comment 3 Title

Post 3 ──┬── Comment 1 Title
         │── Comment 2 Title
         └── Comment 3 Title

...(等)

无论我尝试过什么组合,我都无法限制每个帖子的嵌套 cmets 数量(我的限制总是限制 cmets 的总数,而不是基于每个帖子)。 此外,我的选择无法仅从 cmets 加载标题。如果有经验的人有任何意见,将不胜感激。

PS:上面已经提出了建议,但为了更清楚,这是我的模型:

  schema "posts" do
    field :title, :string
    field :slug, :string
    field :active, :boolean, default: true
    has_many :comments, App.Comment
    timestamps()
  end

  schema "comments" do
    field :title, :string
    field :body, :string
    field :email, :string
    field :meta, :map
    field :active, :boolean, default: false
    belongs_to :post, App.Post
    timestamps()
  end

PPS:更具体地说,我想知道是否可以嵌套限制,与嵌套预加载的方式相同:

query = from Post, preload: [:file, :image, {:comments, [:user, :icon]}], limit: [10, {:comments: 3}]

该预加载会在cmets中预加载嵌套的用户和图标列,但限制显然不适用于嵌套记录。

【问题讨论】:

  • 我可能会为此创建一个数据库视图并为它创建一个 ecto 模式并简单地使用它。
  • 我也在考虑尝试原始查询,但希望看到原生 Ecto 方式。
  • 谢谢@JustinWood,我好像被困住了:)
  • 您可以遍历所有帖子并为每个帖子执行特定的预加载。不过,这是一个 N+1 查询,很不幸。

标签: elixir phoenix-framework ecto


【解决方案1】:

你可以做一个“伪”版本,因为我没有时间实际检查代码,但它会让你开始。

有其他选择,所以在这种情况下如何去由你决定。

首先你创建一个像这样的视图:

 create view posts_with_last_comments as
   select
     p.*,
     (select array_agg(title) from comments where post_id = p.id order by inserted_at limit 3) as last_titles
   from
     posts p

然后在您的应用中执行以下操作:

query = from p in "posts_with_comments"
posts = MyApp.Repo.all(query)

还请注意,我尝试使用 postgresql 语法,这可能会因其他数据库而改变。

【讨论】:

  • 谢谢,这似乎是唯一明智的方法。我认为使用大量的连接和联合也是可能的,但我无法完全理解它。一路Postgres。 :)
  • @Encho 是的,经常有替代品,但这个看起来就像他们来的那样清晰和简单,所以我想我更喜欢这个
【解决方案2】:

没有对此进行测试,但我认为可以在预加载时使用查询。但是我对语法有点不确定。

query = from Post, preload: [:file, :image, {:comments, from(c in Comment, limit: 10), [:user, :icon]}], limit: 10

看看这里的第三个例子。 https://hexdocs.pm/ecto/Ecto.Repo.html#c:preload/3

【讨论】:

  • 谢谢你的回答,我试过了;但是 ":cmets, from(c in Comment, limit: 3)" 将帖子数量限制为 3,而不是 cmets。也许是一个错误?
猜你喜欢
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 2014-01-09
  • 1970-01-01
相关资源
最近更新 更多