part-5 · 插件生态与扩展

Dataview 专题:用查询语言唤醒沉睡的笔记

从元数据到 DQL 语法,再到 DataviewJS,系统掌握 Obsidian 最强大的数据查询引擎。

如果说 Obsidian 是一座堆满笔记的图书馆,那 Dataview 就是那位记得每本书位置和标签的图书管理员。它为 Markdown 文件建立了一个高性能索引,让你用一种类似 SQL 的查询语言(DQL),从全仓库的笔记里实时检索、过滤、排序、分组。本篇带你从元数据起步,一路走到 DQL 全语法与 DataviewJS 门口。

Dataview 是什么

Dataview(作者 blacksmithgu)是一个”查询引擎”而非”编辑器”——它只读取、不改写你的笔记。它会在后台扫描整个仓库,把笔记的属性、列表、任务都建成索引,然后在 ```sql 代码块里渲染出动态视图。视图随笔记内容变化自动更新,无需手动维护。

元数据从哪里来

Dataview 能查询的前提,是笔记里有”字段(field)“——即一对键值。字段有三个来源:

1. Frontmatter(YAML 属性):写在笔记最顶部 --- 之间的内容,会自动成为字段。这是最规范的来源。

---
title: 项目凤凰
status: 进行中
due: 2026-08-15
priority: 5
tags:
  - project
---

这里 statusduepriority 都成了可查询字段。注意 YAML 里一个冒号即可。

2. 行内字段(Inline Fields):用 键:: 值 的双冒号语法,写在正文任意位置。

本周进度:: 70%
[心情:: 满意] 今天的效率不错。

独占一行的字段用 键:: 值;嵌在句子里或写在任务/列表项上的,要用方括号包起来 [键:: 值]。注意是双冒号,这是与 frontmatter 最关键的区别。

3. 隐式字段:Dataview 自动索引的内容,无需你手动添加。每篇笔记都自带一组 file.* 字段,比如 file.name(文件名)、file.ctime(创建时间)、file.mtime(修改时间)、file.tags(标签)、file.lists(列表项)、file.tasks(任务)、file.day(从文件名或属性推断的日期)等。

DQL 查询结构

每条 DQL 查询都遵循同一骨架:一个查询类型开头,可选一个 FROM 指定来源,再跟任意数量的数据命令。只有查询类型是必填的。

```sql
<查询类型> <字段>
FROM <来源>
<数据命令> <表达式>
<数据命令> <表达式>

### FROM——圈定范围

`FROM` 接受标签、文件夹或链接作为来源,可用 `AND`/`OR`/`NOT` 组合:

```sql
LIST
FROM "项目/凤凰"            -- 某文件夹及其子文件夹
FROM #project               -- 带某标签的笔记
FROM #status/open OR #status/wip
FROM (#project AND "30 工作") OR outgoing([[看板]])

FROM 只能出现一次,且必须紧跟查询类型之后。

四种查询类型

  • LIST:项目符号列表,可附带一个字段。
  • TABLE:表格,每行一篇笔记,可指定多列字段。
  • TASK:交互式任务清单,可直接勾选。
  • CALENDAR:月历视图,按日期打点。
TABLE status, due, priority
FROM #project
WHERE status = "进行中"
SORT priority DESC

数据命令五件套

WHERE 过滤、Sort 排序、GROUP BY 分组、LIMIT 限量、FLATTEN 展开。除 FROM 外,它们可多次出现、按书写顺序执行。

  • WHERE:按字段筛选。

    LIST
    WHERE due AND due < date(today)
    
  • SORT:按字段升降序,ASC/DESC

    LIST FROM #project
    SORT file.ctime DESC
    LIMIT 10
    
  • GROUP BY:按字段打包,分组后原始行变成 rows 数组。

    TASK
    WHERE !completed
    GROUP BY file.link
    SORT rows.file.ctime ASC
    
  • LIMIT:只保留前 N 条结果。

  • FLATTEN:把一个多值字段”拆”成多行,常用于展开列表项。

    TABLE L.text AS "要点"
    FROM "日记"
    FLATTEN file.lists AS L
    WHERE contains(L.text, "想法")
    

常用函数

Dataview 内置了大量函数,可在 WHERESORTTABLE 列等任何表达式里使用。挑最常用的几类:

构造与转换

  • date(any):把字符串或链接解析为日期对象,如 date("2026-08-15")
  • dur(any):解析时长,如 dur("8 hours")
  • number(string)string(any)typeof(any):类型转换与判断。
  • link(path, [display]):构造一个内链对象。

字符串

  • contains(object|list|string, value):判断是否包含某值,最常用。
  • split(string, delimiter, [limit]):按分隔符切分字符串。
  • regexmatch(pattern, string):正则匹配,返回布尔值。
  • regexreplace(string, pattern, replacement):正则替换。
  • lower(s)upper(s)replace(s, old, new)startswith(s, prefix)

日期与时长

  • date(today)date(now):今天、此刻。
  • dateformat(date, string):按 Luxon token 格式化日期。
  • dur(...) 可做日期运算,如 date(today) - file.ctime 算出”距今多久”。

工具

  • default(field, value):字段为空时给默认值。
  • choice(bool, left, right):三元表达式,choice(priority > 3, "重要", "普通")
  • length(array)sort(list)reverse(list)unique(array)join(array, sep)

[!note] 函数向量化 大多数函数既能作用于单个值,也能作用于列表——传列表时,函数会对每个元素分别求值并返回新列表。比如 lower(["YES", "NO"]) 会得到 ["yes", "no"]

实战查询示例库

未完成且已逾期的任务

TASK
WHERE !completed AND due AND due < date(today)
SORT due ASC

近 7 天创建的笔记

TABLE file.ctime AS "创建于", file.tags AS "标签"
WHERE file.ctime >= date(today) - dur(7 days)
SORT file.ctime DESC

按状态分组的项目

TABLE rows.file.link AS "项目"
FROM #project
GROUP BY status
SORT status ASC

读书笔记评分榜

TABLE rating AS "评分", author AS "作者"
FROM "书籍"
WHERE rating
SORT rating DESC
LIMIT 10

把每条列表项展开成一行

TABLE L.text AS "金句"
FROM #摘抄
FLATTEN file.lists AS L
WHERE contains(L.text, "努力")

DataviewJS:更自由的进阶玩法

当 DQL 不够用时,可以用 ```javascript 代码块写 JavaScript。它把 Dataview 的索引数据通过 dv 对象暴露给你,能实现 DQL 做不到的复杂逻辑:

```javascript
dv.table(
  ["笔记", "字数"],
  dv.pages("#project")
    .map(p => [p.file.link, p.file.size])
    .sort((a, b) => b[1] - a[1])
    .slice(0, 10)
)

常用 API:`dv.pages(source)` 取页面、`dv.table(headers, data)` 画表、`dv.list(values)` 画列表、`dv.taskList(pages)` 画任务、`dv.markdownTable()` 输出纯 Markdown。

> [!warning] DataviewJS 的安全边界
> DataviewJS 本质是在你的仓库里执行任意 JavaScript,能力等同于一个插件。因此它默认是关闭的,需在 Dataview 设置里手动开启"Enable JavaScript Queries"。只运行你看得懂或来自可信来源的脚本,不要随意复制网上的 dataviewjs 代码就跑。

## Dataview vs Bases

Obsidian 1.9 引入的核心插件 Bases,和 Dataview 解决的是同一类问题——把笔记按属性组织成结构化视图。它们的取舍如下:

| 维度 | Dataview | Bases |
|---|---|---|
| 出处 | 社区插件 | 官方核心插件 |
| 查询方式 | 类 SQL 代码块,文本驱动 | 图形化视图,所见即所得 |
| 灵活度 | 极高,支持函数、JS、FLATTEN 等 | 适中,覆盖常见排序/过滤/分组 |
| 上手难度 | 需学 DQL 语法,门槛略高 | 拖拽点选,对新手友好 |
| 数据修改 | 只读,不能直接改属性 | 可在视图里直接编辑属性 |
| 移动端 | 支持,但复杂查询略卡 | 原生支持,体验统一 |

简单结论:**想要"看板式"直观管理和就地编辑,用 Bases;想要极致灵活的动态查询和复杂逻辑,用 Dataview。** 二者并不互斥,完全可以并存——日常清单交给 Bases,复杂报表交给 Dataview。

Dataview 的学习曲线确实存在,但每一分投入都会以"自动化"的形式偿还。从今天起,给你的重要笔记加上 frontmatter,再写第一条 `LIST FROM #project` 试试——你会感到笔记"活"了起来。