Skip to content

Latest commit

 

History

History
78 lines (58 loc) · 1.85 KB

2021-11-22-til-cleaner-queries-with-ecto-map.md

File metadata and controls

78 lines (58 loc) · 1.85 KB
Error in user YAML: (<unknown>): could not find expected directive name while scanning a directive at line 1 column 1
---
%{
author: "Yuri Oliveira",
author_link: "https://github.com/yuriploc",
tags: ["ecto"],
date: ~D[2021-11-22],
title: "TIL: Cleaner queries with Ecto `map`",
excerpt: """
Today I learned how to write cleaner `Ecto` select queries with the help of `Ecto.Query.map`.
"""
}

---

TIL: 使用 Ecto 的 map 进行更干净的查询

当处理一张大表时,一个常见的做法是避免使用 SELECT * 以更好地利用数据库索引和资源。

因此,不要这样写:

query = from p in Post
Repo.all(query)

为了避免得到比我们需要的更多的数据,我们可以明确地告诉 Ecto(和 DB)我们希望它返回哪些列:

query = from p in Post, select: %{id: p.id, title: p.title, category_id: p.category_id}
Repo.all(query)

但为什么我们要如此明确地重复键和值呢?难道没有一个更好的方法吗?

事实证明,Ecto.Query 已经用 map/2 函数为我们解决了这个问题。所以像这样:

query = from p in Post, select: %{id: p.id, title: p.title, category_id: p.category_id}
Repo.all(query)

变成这样:

query = from p in Post, select: map(p, [:id, :title, :category_id])
Repo.all(query)

或者,在 Pipeline 中:

Post
|> select([p], %{id: p.id, title: p.title, category_id: p.category_id})
|> Repo.all()
Post
|> select([p], map(p, [:id, :title, :category_id]))
|> Repo.all()

当在一个函数中使用它时,我们甚至可以有动态字段,比如:

def filter_posts_by_id(posts_ids, fields \\ [:id, :title, :category_id]) do
  Post
    |> where([p], p.id in ^posts_ids)
    |> select([p], map(p, ^fields))
    |> Repo.all()
end

由于 Ecto.Query.map/2 函数和管道的使用,我们最终得到了干净、可组合和高度可读的代码。

享受 Ecto 吧!

感谢 Groxio 导师们的支持