collections.Where
按指定的 key、运算符和值筛选给定切片,返回满足条件的元素。
用法
where 函数返回给定切片,并移除不满足比较条件的元素。比较条件由 KEY、OPERATOR 和 VALUE 三个参数构成:
collections.Where SLICE KEY [OPERATOR] VALUE
--------------------
比较条件如果不提供 OPERATOR 参数,Hugo 会按相等进行比较。例如:
{{ $pages := where .Site.RegularPages "Section" "books" }}
{{ $books := where hugo.Data.books "genres" "suspense" }}参数
where 函数接收三到四个参数。OPERATOR 参数是可选的。
SLICE- (
[]any)一个页面集合,或由映射构成的切片。 KEY- (
string)用于与VALUE比较的页面或映射值的 key。对于页面集合,常用的比较 key 有Section、Type和Params。要与页面Params映射中的成员比较,请按下文所示链式书写子 key:{{ $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 |
当参与比较的值之一是切片(或两者都是)时,请按下文所述使用 in、not in 或 intersect 运算符。
运算符
可使用以下任一逻辑运算符:
=,==,eq- (
bool)判断给定字段值是否等于VALUE。 !=,<>,ne- (
bool)判断给定字段值是否不等于VALUE。 >=,ge- (
bool)判断给定字段值是否大于或等于VALUE。 >,gttrue判断给定字段值是否大于VALUE。<=,le- (
bool)判断给定字段值是否小于或等于VALUE。 <,lt- (
bool)判断给定字段值是否小于VALUE。 in- (
bool)判断给定字段值是否为VALUE的成员。比较字符串与切片,或字符串与字符串。 not in- (
bool)判断给定字段值是否不是VALUE的成员。比较字符串与切片,或字符串与字符串。 intersect- (
bool)判断给定字段值(一个切片)是否与VALUE有一个或多个共同元素。 like- (
bool)判断给定字段值是否匹配VALUE中指定的正则表达式。用like运算符比较string值。用其他数据类型与正则表达式比较时,like运算符返回false。
示例
以下示例演示了使用各种运算符和数据类型的比较。
字符串比较
将给定字段的值与 string 比较:
{{ $pages := where .Site.RegularPages "Section" "eq" "books" }}
{{ $pages := where .Site.RegularPages "Section" "ne" "books" }}数值比较
{{ $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 }}成员比较
例如,要返回 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 }}交集比较
将 slice 与 slice 比较,返回具有共同值的元素。这在比较分类法(taxonomy)术语时经常用到。
例如,要返回 genres 分类法中的任一术语为 “suspense” 或 “romance” 的页面切片:
{{ $books := where site.RegularPages "Section" "eq" "books" }}
{{ $genres := slice "suspense" "romance" }}
{{ $pages := where $books "Params.genres" "intersect" $genres }}正则表达式比较
要返回 author 页面参数以 “victor” 或 “Victor” 开头的页面切片:
{{ $pages := where .Site.RegularPages "Params.author" "like" `(?i)^victor` }}指定正则表达式时,请使用原始字符串字面量(反引号)而不是解释型字符串字面量(双引号),以简化语法。使用解释型字符串字面量时,必须转义反斜杠。
Go 的正则表达式包实现了 RE2 语法。大致来说,RE2 语法是 PCRE 所接受语法的一个子集,并且有若干注意事项。注意不支持 RE2 的 \C 转义序列。
日期比较
比较预定义的前置元数据(front matter)日期,或自定义的前置元数据日期。
预定义日期
有四个预定义的前置元数据日期:date、publishDate、lastmod 和 expiryDate。无论前置元数据采用哪种数据格式(TOML、YAML 还是 JSON),它们都是 time.Time 值,因此可以精确比较。
例如,要返回在当前年份之前创建的页面切片:
{{ $startOfYear := time.AsTime (printf "%d-01-01" now.Year) }}
{{ $pages := where .Site.RegularPages "Date" "lt" $startOfYear }}自定义日期
对于自定义的前置元数据日期,比较方式取决于前置元数据的数据格式(TOML、YAML 或 JSON)。
使用 TOML 时,日期值是一等公民。TOML 有日期数据类型,而 JSON 和 YAML 没有。如果给 TOML 日期加上引号,它就是字符串;如果不加引号,它就是 time.Time 值,可以精确比较。
在下面的 TOML 示例中,注意事件日期没有加引号。
+++
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" }}可移植的 section 比较
这一点对主题作者很有用:使用 where 函数配合 Site 对象上的 MainSections 方法,可以避免硬编码 section 名称。
{{ $pages := where .Site.RegularPages "Section" "in" .Site.MainSections }}用这种写法,主题作者可以要求用户在自己的项目配置中指定主要 section:
mainSections = ['blog','galleries']如果项目配置中没有定义 mainSections,MainSections 方法会返回只含一个元素的切片——即页面最多的顶级 section。
布尔值/未定义值比较
考虑下面这样的项目结构:
content/
├── posts/
│ ├── _index.md
│ ├── post-1.md <-- 前置元数据:exclude = false
│ ├── post-2.md <-- 前置元数据:exclude = true
│ └── post-3.md <-- 前置元数据:未定义 exclude
└── _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>要把字段未定义的页面从布尔_不等_测试中排除:
- 用布尔比较创建一个切片
- 用
nil比较创建一个切片 - 用
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>