从 YAML 与行内字段开始,分清页面、任务和四种输出,再走完来源、条件、排序与表达式。
先分清正文、字段与查询#
写在笔记里的内容,并不会自动变成可以筛选的字段。Dataview 会索引文件信息、列表和任务,也能读取显式标注的属性;普通正文仍主要由阅读和全文搜索来理解。要找“还在进行、优先级较高的项目”,就应该先把状态和优先级写成结构化数据。[1]
DQL 是 Dataview Query Language。它通过 LIST、TABLE、TASK、CALENDAR 指定结果形式,再用来源、条件和排序组织结果。下面使用虚构的 Studio 笔记库:项目放在 Studio/Projects,阅读记录放在 Studio/Library。示例用于解释语法,没有在某个真实知识库中运行。阅读这些查询之前,需要 Obsidian 中已启用 Dataview;网站只展示代码,不会执行查询。
同一份记录,先有稳定的字段#
下面是假想项目 Studio/Projects/Atlas.md 的开头。YAML frontmatter 必须位于文件顶部,使用单冒号定义字段。status 是文本,priority 是数字,archived 是布尔值,topics 是列表;due 使用 ISO 日期。不要把数字写成“高”再按数值比较,也不要在同一个字段中混用日期与“下周”这样的描述。[7]
---
type: project
status: active
priority: 3
archived: false
due: 2030-05-12
topics:
- search
- interface
tags:
- demo/project
---
# Atlas
reviewed:: 2030-05-02
这轮原型的 [confidence:: 4],还需要补一组边界条件。
- [ ] 检查空结果页面 [due:: 2030-05-10]正文中的行内字段使用双冒号;独立一行可以写 reviewed:: 值,嵌入句子或任务时用方括号。frontmatter 描述整篇页面,任务上的 [due:: ...] 描述这一条任务。两者可以并用,但不宜随手把同一个业务事实写在多个位置,再期待插件替你判断哪个更新。[1]
示例统一使用小写英文字段名,是为了让复制、检索和维护更稳定。Dataview 支持中文字段;带空格的字段还有规范化名称或 row 访问方式。显示给读者的中文列名可以在查询中使用 AS 定义,不必让数据键名承担排版。
不用手写,也已经存在的 file 字段#
| 字段 | 它回答什么 |
|---|---|
file.name / file.link | 文件叫什么,以及如何回到原笔记 |
file.folder | 笔记所在的库内目录 |
file.ctime / file.mtime | 文件的创建、最后修改时间,包含时刻 |
file.cday / file.mday | 对应时间的日期部分 |
file.tags / file.etags | 展开父级后的标签,以及仅显式写出的标签 |
file.tasks | 页面里索引到的任务列表 |
这些隐式字段集中在 file 对象中,不要求先在 YAML 写一遍。若一篇笔记使用 #demo/project,file.tags 会包含父级 #demo 和完整标签;file.etags 保留显式标签。做标签统计前要决定自己统计哪一种,否则上一级分类也会进入结果。[2]
修改时间适合回答“最近动过哪些文件”,不能直接表示“最近学会哪些知识”。格式化、同步或属性调整也可能改变文件时间。业务上的阅读完成日期、复核日期,最好使用 date_finished、reviewed 这样的显式字段,而不是从文件时间猜。
四种输出,查询的单位也不同#
LIST、TABLE 和 CALENDAR 以页面为单位;TASK 以任务为单位。把同一份数据换一个标题,并不等于查询层级已经改变。[3]
```dataview
LIST status
FROM "Studio/Projects"
```LIST 默认显示页面链接,status 是跟在链接后的一个附加值。它适合清单;要同时比较多个属性,就用 TABLE。TABLE 默认已有标识列,下面只需写状态和优先级。AS 修改显示名,不会重命名源笔记里的字段。
```dataview
TABLE status AS "状态", priority AS "优先级"
FROM "Studio/Projects"
```如果想自己控制第一列,可以写 TABLE WITHOUT ID file.link AS "项目", status AS "状态"。这里显式加回链接,否则读者只看到属性值,难以回到记录。
```dataview
TASK
FROM "Studio/Projects"
WHERE !completed AND due = date(today)
```这条 TASK 查询列出未完成且今天到期的任务;前提是任务有可识别的 due 日期。没有到期日的待办不会因为“未完成”就自动出现在今天列表里。
```dataview
CALENDAR due
FROM "Studio/Projects"
WHERE due != null
```CALENDAR 把页面按某个日期放入日历,不是在此处画任务甘特图。日期缺失的页面无法定位;如果需要看任务到期情况,应先确认任务层级和页面层级,不能把两种 due 混作一列。
FROM 的组合,先判断交集还是并集#
FROM 限定初始范围。目录来源使用相对于笔记库根部的完整路径,包含子目录;加双引号且不要留末尾斜线。标签来源使用 #,链接来源可以利用页面之间的关系。[4]
| 来源写法 | 含义 |
|---|---|
FROM "Studio/Projects" | 这个目录及其子目录中的页面 |
FROM #demo/project | 使用该标签及其子标签的页面 |
FROM [[Atlas]] | 链接到 Atlas 的页面 |
FROM outgoing([[Atlas]]) | Atlas 链接出去的页面 |
```dataview
LIST
FROM "Studio/Projects" AND #demo/project
WHERE archived = false
```AND 要同时满足两边,是交集;OR 满足任一边,是并集。上一例要求“在项目目录里,并且带项目标签”。如果改成 OR,目录外带该标签的页面也会进来。排除可以写 #demo/project AND !#demo/retired;组合较多时,使用括号写清范围,例如 ("Studio/Projects" OR "Studio/Library") AND !#demo/retired。
来源语法与普通字段表达式各有位置。FROM #demo/project 是选标签来源;WHERE status = "active" 是筛记录字段。不要把后者塞进 FROM,也不要把标签来源的 # 语法照搬成文本字段值。
筛选、排序、截取,按问题排顺序#
```dataview
TABLE status AS "状态", priority AS "优先级", due AS "到期日"
FROM "Studio/Projects"
WHERE status = "active" AND priority >= 2
SORT priority DESC, due ASC
LIMIT 5
```先找 active 且优先级至少为 2 的项目,再按优先级降序;同优先级按到期日升序,最后取五条。DESC 表示从大到小,ASC 表示从小到大。若到期日是必要依据,应再加入 due != null,把未填日期的项目另列检查。
数据命令按书写顺序处理。把 LIMIT 放在 SORT 前,会先截出一部分再排序,不能保证得到整个候选集里最高的五条。这和把 WHERE 放在分组前后会处理不同的数据形状一样,顺序本身属于查询的含义。[5]
布尔判断也要区分“明确为假”和“没有值”。WHERE archived = false 要求值为 false;WHERE !archived 还可能把缺失值纳入。字段完整度未知时,先用 TABLE 展示原值,再选判断方式,比直接把所有空值看成“未归档”更容易发现数据问题。
函数改善显示,不能替代数据约定#
```dataview
TABLE default(status, "待补状态") AS "状态",
choice(priority >= 3, "优先处理", "正常排队") AS "提示",
join(topics, ", ") AS "主题"
FROM "Studio/Projects"
```default 在值为 null 时给显示用的后备值;choice 根据条件选择两个结果;join 把列表连接成文本。它们适合让表格更易读,但不会把“待补状态”写回 YAML,也不会替你确认这个项目实际是什么状态。[6]
字符串处理还有 lower、upper、startswith;contains 对不同类型有不同含义,列表可用来判断成员,文本可用来查包含的片段。像 topics 这样的列表,应保持各笔记写法一致,不要一篇写 YAML 列表、另一篇写整段逗号分隔文本。数学表达式也需要数值输入,例如预算折扣可以写 price * 0.9,不能先把 price 存成“约一百元”再期待同样计算。
查询为空时,按最小步骤检查:先只保留 LIST 与 FROM,确认来源;再临时用 TABLE 展示 status、priority、due;最后逐条加回 WHERE、SORT、LIMIT。页面没有进来源、字段没有索引、类型不一致和条件太严格,都会显示为“没有结果”,它们需要不同的修正。
参考与延伸
- Dataview:添加元数据 ↗
- Dataview:页面隐式字段 ↗
- Dataview:四种查询类型 ↗
- Dataview:查询来源 ↗
- Dataview:数据命令与顺序 ↗
- Dataview:函数参考 ↗
- Dataview:字段类型 ↗
根据技术笔记重新整理,示例使用通用名称。