collections.Where

where 函數會返回給定的集合,並移除不滿足比較條件的元素。比較條件由 KEYOPERATORVALUE 參數組成:

collections.Where COLLECTION KEY [OPERATOR] VALUE
                             --------------------
                             比較條件

如果沒有提供 OPERATOR 參數,Hugo 會測試等值比較。例如:

{{ $pages := where .Site.RegularPages "Section" "books" }}
{{ $books := where .Site.Data.books "genres" "suspense" }}

參數

where 函數接受三個或四個參數。OPERATOR 參數是可選的。

COLLECTION
(any) 一個 [頁面集合] 或 [切片] 的 [映射]。
KEY
(string) 要與 VALUE 比較的頁面或映射值的鍵。對於頁面集合,常見的比較鍵是 SectionTypeParams。要與頁面 Params 映射中的成員比較,請 [鏈接] 子鍵,如下所示:
{{ $result := where .Site.RegularPages "Params.foo" "bar" }}
OPERATOR
(string) 邏輯比較 運算符
VALUE
(any) 要比較的值。要比較的值必須具有可比較的資料類型。例如:
比較 結果
"123" "eq" "123" true
"123" "eq" 123 false
false "eq" "false" false
false "eq" false true

當其中一個或兩個要比較的值為切片時,請使用 innot inintersect 運算符,如下所示。

運算符

使用以下任意邏輯運算符:

=, ==, eq
(bool) 報告給定欄位值是否等於 VALUE
!=, <>, ne
(bool) 報告給定欄位值是否不等於 VALUE
>=, ge
(bool) 報告給定欄位值是否大於或等於 VALUE
>, gt
true 報告給定欄位值是否大於 VALUE
<=, le
(bool) 報告給定欄位值是否小於或等於 VALUE
<, lt
(bool) 報告給定欄位值是否小於 VALUE
in
(bool) 報告給定欄位值是否是 VALUE 的成員。比較字串對切片或字串對字串。請參見 詳細信息
not in
(bool) 報告給定欄位值是否不是 VALUE 的成員。比較字串對切片或字串對字串。請參見 詳細信息
intersect
(bool) 報告給定欄位值(切片)是否包含與 VALUE 共有的元素。請參見 詳細信息
like New in v0.116.0
(bool) 報告給定欄位值是否符合 VALUE 中指定的正則表達式。使用 like 運算符比較 string 值。當將其他資料類型與正則表達式比較時,like 運算符會返回 false

字串比較

比較給定欄位的值與 string

{{ $pages := where .Site.RegularPages "Section" "eq" "books" }}
{{ $pages := where .Site.RegularPages "Section" "ne" "books" }}

數字比較

比較給定欄位的值與 intfloat

{{ $books := where site.RegularPages "Section" "eq" "books" }}

{{ $pages := where $books "Params.price" "eq" 42 }}
{{ $pages := where $books "Params.price" "ne" 42.67 }}
{{ $pages := where $books "Params.price" "ge" 42 }}
{{ $pages := where $books "Params.price" "gt" 42.67 }}
{{ $pages := where $books "Params.price" "le" 42 }}
{{ $pages := where $books "Params.price" "lt" 42.67 }}

布林值比較

比較給定欄位的值與 bool

{{ $books := where site.RegularPages "Section" "eq" "books" }}

{{ $pages := where $books "Params.fiction" "eq" true }}
{{ $pages := where $books "Params.fiction" "eq" false }}
{{ $pages := where $books "Params.fiction" "ne" true }}
{{ $pages := where $books "Params.fiction" "ne" false }}

成員比較

比較 scalarslice

例如,要返回一個頁面集合,其中 color 頁面參數是 “red” 或 “yellow”:

{{ $fruit := where site.RegularPages "Section" "eq" "fruit" }}

{{ $colors := slice "red" "yellow" }}
{{ $pages := where $fruit "Params.color" "in" $colors }}

要返回一個頁面集合,其中 “color” 頁面參數既不是 “red” 也不是 “yellow”:

{{ $fruit := where site.RegularPages "Section" "eq" "fruit" }}

{{ $colors := slice "red" "yellow" }}
{{ $pages := where $fruit "Params.color" "not in" $colors }}

交集比較

比較 sliceslice,返回具有共同值的集合元素。這通常用於比較分類法術語。

例如,要返回一個頁面集合,其中 “genres” 分類法中的任何術語為 “suspense” 或 “romance”:

{{ $books := where site.RegularPages "Section" "eq" "books" }}

{{ $genres := slice "suspense" "romance" }}
{{ $pages := where $books "Params.genres" "intersect" $genres }}

正則表達式比較

New in v0.116.0

要返回一個頁面集合,其中 “author” 頁面參數以 “victor” 或 “Victor” 開頭:

{{ $pages := where .Site.RegularPages "Params.author" "like" `(?i)^victor` }}

在指定正則表達式時,請使用原始的 string literal(反引號),而非解釋過的字串字面量(雙引號),以簡化語法。使用解釋過的字串字面量時,您必須對反斜線進行轉義。

Go 的正則表達式套件實現了 [RE2 語法]。RE2 語法是接受的 PCRE 語法的一個子集,粗略來說,並且有各種 caveats。請注意,RE2 不支援 \C 轉義序列。

日期比較

預設日期

有四個預設的 Front Matter 日期:datepublishDatelastmodexpiryDate。無論使用何種 Front Matter 資料格式(TOML、YAML 或 JSON),這些都是 time.Time 類型值,可以進行精確的比較。

例如,返回創建時間早於當前年份的頁面集合:

{{ $startOfYear := time.AsTime (printf "%d-01-01" now.Year) }}
{{ $pages := where .Site.RegularPages "Date" "lt" $startOfYear }}

自訂日期

使用自訂的 front matter 日期時,比較操作會依照 front matter 數據格式(TOML、YAML 或 JSON)來決定。

在 TOML 格式中,日期值是第一類別(first-class)。TOML 擁有日期數據類型,而 JSON 和 YAML 沒有。如果您引用 TOML 日期,它會是字串。如果您不引用 TOML 日期值,它將會是 time.Time 型別,從而可以進行精確的比較。

在下列的 TOML 範例中,請注意事件日期並未被引用。

content/events/2024-user-conference.md
+++
title = '2024 User Conference'
eventDate = 2024-04-01
+++

要返回一組未來的事件:

{{ $events := where .Site.RegularPages "Type" "events" }}
{{ $futureEvents := where $events "Params.eventDate" "gt" now }}

當使用 YAML、JSON 或引用的 TOML 值時,自訂日期會是字串;您無法將它與 time.Time 型別的值進行比較。如果自訂日期格式在不同頁面間一致,則可以進行字串比較。為了保險起見,透過遍歷整個集合來過濾頁面:

{{ $events := where .Site.RegularPages "Type" "events" }}
{{ $futureEvents := slice }}
{{ range $events }}
  {{ if gt (time.AsTime .Params.eventDate) now }}
    {{ $futureEvents = $futureEvents | append . }}
  {{ end }}
{{ end }}

Nil 比較

要返回一組包含 “color” 參數的頁面,並與 nil 比較:

{{ $pages := where .Site.RegularPages "Params.color" "ne" nil }}

要返回一組不包含 “color” 參數的頁面,並與 nil 比較:

{{ $pages := where .Site.RegularPages "Params.color" "eq" nil }}

在上述的範例中,請注意 nil 並未被引用。

嵌套比較

以下兩者等價:

{{ $pages := where .Site.RegularPages "Type" "tutorials" }}
{{ $pages = where $pages "Params.level" "eq" "beginner" }}
{{ $pages := where (where .Site.RegularPages "Type" "tutorials") "Params.level" "eq" "beginner" }}

可攜式區塊比較

對於主題作者來說,可以避免硬編碼區塊名稱,透過在 Site 物件上使用 where 函數與 MainSections 方法來達成。

{{ $pages := where .Site.RegularPages "Section" "in" .Site.MainSections }}

通過這個結構,主題作者可以指示使用者在站點配置中指定主區塊:

hugo.
     
params:
  mainSections:
  - blog
  - galleries
[params]
  mainSections = ['blog', 'galleries']
{
   "params": {
      "mainSections": [
         "blog",
         "galleries"
      ]
   }
}

如果 params.mainSections 在站點配置中未被定義,則 MainSections 方法會返回一個包含單一元素的切片—即包含最多頁面的頂層區塊。

布林值/未定義比較

考慮以下網站內容:

content/
├── posts/
│   ├── _index.md
│   ├── post-1.md  <-- front matter: exclude = false
│   ├── post-2.md  <-- front matter: exclude = true
│   └── post-3.md  <-- front matter: exclude not defined
└── _index.md

前兩個頁面有 “exclude” 欄位,但最後一個頁面並未定義這個欄位。在進行 相等 測試時,第三個頁面將 被排除;進行 不等 測試時,第三個頁面將 被包含

相等測試

此模板:

<ul>
  {{ range where .Site.RegularPages "Params.exclude" "eq" false }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

將渲染為:

<ul>
  <li><a href="/posts/post-1/">Post 1</a></li>
</ul>

此模板:

<ul>
  {{ range where .Site.RegularPages "Params.exclude" "eq" true }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

將渲染為:

<ul>  
  <li><a href="/posts/post-2/">Post 2</a></li>
</ul>

不等測試

此模板:

<ul>
  {{ range where .Site.RegularPages "Params.exclude" "ne" false }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

將渲染為:

<ul>
  <li><a href="/posts/post-2/">Post 2</a></li>
  <li><a href="/posts/post-3/">Post 3</a></li>
</ul>

此模板:

<ul>
  {{ range where .Site.RegularPages "Params.exclude" "ne" true }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

將渲染為:

<ul>
  <li><a href="/posts/post-1/">Post 1</a></li>
  <li><a href="/posts/post-3/">Post 3</a></li>
</ul>

排除未定義欄位的頁面,進行布林 不相等 測試:

  1. 使用布林比較創建集合
  2. 使用 nil 比較創建集合
  3. 使用 collections.Complement 函數將第二個集合從第一個集合中扣除。

範例模板:

{{ $p1 := where .Site.RegularPages "Params.exclude" "ne" true }}
{{ $p2 := where .Site.RegularPages "Params.exclude" "eq" nil  }}
<ul>
  {{ range $p1 | complement $p2 }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

渲染後結果為:

<ul>
  <li><a href="/posts/post-1/">Post 1</a></li>
</ul>

範例模板:

{{ $p1 := where .Site.RegularPages "Params.exclude" "ne" false }}
{{ $p2 := where .Site.RegularPages "Params.exclude" "eq" nil  }}
<ul>
  {{ range $p1 | complement $p2 }}
    <li><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></li>
  {{ end }}
</ul>

渲染後結果為:

<ul>
  <li><a href="/posts/post-1/">Post 2</a></li>
</ul>

這樣的做法是將兩組頁面進行分開:一組具有布林 exclude 欄位,另一組 exclude 欄位未定義,再將未定義欄位的集合從布林比較結果中扣除,以達到想要的過濾邏輯。