☰
基于 Dataview 的 annotated 字段与任务分组查询实战:从 test-vault 示例到源码级解析
2026/9/25 5:08:25 网站建设 项目流程
  • 前端
  • 知识管理
  • 数据分析

【免费下载链接】obsidian-dataview

A data index and query language over Markdown files, for https://obsidian.md/.

项目地址:https://gitcode.com/gh_mirrors/ob/obsidian-dataview
点击查看免费下载

在 Obsidian 中使用 Dataview 管理任务时,annotated隐式字段可以快速筛选出「带元数据注释的任务」,而group by子句则能把任务按任意字段分组呈现。本文以仓库内 test-vault 中的 Annotated Tasks.md 为骨架,结合官方文档与源码实现,讲解如何用task where annotated与task group by p两类查询驾驭任务元数据。

一、关联文档是什么:一个可运行的查询示例库

Annotated Tasks.md 是仓库test-vault/tasks/目录下的一个真实可运行的示例笔记,文件内容本身只有两段 Dataview 查询:

task where annotated

以及分组版本:

task where p group by p

它演示了 Dataview 任务查询的两个核心能力:

  1. 利用annotated隐式字段过滤:只列出「文本中包含元数据字段」的任务;
  2. 利用group by对任务分组:按某个字段(示例中的p)把任务归组展示。

围绕这两段查询,官方文档 Metadata on Tasks and Lists 提供了完整的字段语义说明,源码则给出了底层实现依据。以下逐层展开。

二、annotated是什么:任务级元数据的布尔标志

官方定义

根据文档 Implicit Fields 中的字段表,annotated的定义是:

字段名数据类型说明
annotatedBoolean任务文本中包含任何元数据字段时为true,否则为false。

也就是说,一个任务只要在文本里出现了任意一处内联字段(inline field),它的annotated值即为true;完全没有任何字段注释的普通任务则为false。

源码级验证

在 src/data-model/markdown.ts 的ListItem.serialize方法中,annotated的实现就是一行判断:

annotated: this.fields.size > 0,

即:该列表项(任务或普通列表项)解析出的fields 集合(Map)大小大于 0时,annotated为真。这里的fields来自任务行内所有内联字段的解析结果(见this.fields = this.fields || new Map(),位于 src/data-model/markdown.ts)。对应的序列化接口定义在 src/data-model/serialized/markdown.ts:

annotated?: boolean;

由此可以确认:annotated与任务是否勾选完成无关,只与是否存在字段注释有关。一个未勾选[ ]但带有[due:: 2021-08-29]注释的任务,annotated同样为true。

三、如何让任务变成annotated:内联字段与 Field Shorthands

任务级别的元数据使用与页面相同的内联字段语法(参见 add-metadata.md)。在任务行内书写[key:: value]即可绑定字段到该任务:

- [ ] Hello, this is some [metadata:: value]! - [X] I finished this on [completion:: 2021-08-15].

上面两个任务都包含字段,因此annotated均为true。

Emoji 简写(Field Shorthands)

除了标准内联字段,Dataview 还支持 Tasks 插件风格的 Emoji 日期简写。其特点是省略内联字段的方括号语法(无需写[🗓️:: 2021-08-29]),并映射为文本型字段名:

字段名简写语法
due🗓️YYYY-MM-DD
completion✅YYYY-MM-DD
created➕YYYY-MM-DD
start🛫YYYY-MM-DD
scheduled⏳YYYY-MM-DD

示例:

- [ ] Due this Saturday 🗓️2021-08-29 - [x] Completed last Saturday ✅2021-08-22 - [ ] I made this on ➕1990-06-14 - [ ] Task I can start this weekend 🛫2021-08-29 - [x] Task I finished ahead of schedule ⏳2021-08-29 ✅2021-08-22

需要说明的是,当前版本仅支持上述日期类简写;优先级与重复(recurrence)简写不受支持。由于 Emoji 简写在数据层面也会产生字段,这类任务同样属于annotated = true——因此task where annotated能同时捕获「内联字段注释」与「Emoji 日期简写」两类任务。

四、task where annotated查询详解

基本用法

回到关联文档的第一段查询:

task where annotated

在 TASK 查询中,任务本身就是顶层数据,因此隐式字段可以不带前缀直接使用(参见文档 Accessing Implicit Fields in Queries)。该查询返回所有「包含任意元数据字段」的任务。

若在非 TASK 查询中访问任务字段,则需要通过file.lists/file.tasks间接访问,并借助列表函数(如any)逐项判断:

LIST WHERE any(file.tasks, (t) => t.annotated)

该写法会返回所有「含有带注释任务」的笔记链接。

结合其它任务隐式字段的组合筛选

annotated常与下列任务隐式字段组合使用,形成更精细的筛选条件:

字段名类型含义
statusText[ ]括号内的状态字符,一般为空格(未完成)或x(完成),也支持自定义状态插件
checkedBoolean状态字符非空(即括号内不是空格),不一定等于x
completedBoolean本任务是否被标记为x完成,不考虑子任务;自定义状态(如[-])时checked为真而completed为假
fullyCompletedBoolean本任务及其所有子任务是否全部完成
textText任务纯文本,含字段注释
line/lineCountNumber任务所在行号 / 占用的 Markdown 行数
pathText任务所在文件的完整路径,等价于页面的file.path
sectionLink任务所在章节的链接
tagsList任务文本中的标签
outlinksList任务中定义的链接
linkLink任务附近最近可链接块的链接
childrenList任务的子任务 / 子列表
taskBoolean是否为任务(否则是普通列表项)
annotatedBoolean是否含元数据字段
parentNumber父级任务的所在行号(无则为null)
blockIdText使用^blockId定义的块 ID(无则为null)

例如,筛选「带注释且未完成」的任务:

task where annotated and !completed

任务属性继承:页面字段向上流动

一个容易被忽略的事实是:任务会继承其所在页面的全部字段(文档 Implicit Fields 中的 info 提示)。因此若页面有rating字段,在 TASK 查询中同样可以在任务上访问它。不过要注意,annotated判断的是任务自身文本中的字段(this.fields.size > 0),页面级字段不会让任务的annotated变为true。

五、group by分组查询详解

关联文档中的第二段查询

task where p group by p

在 test-vault 中,p是示例笔记里自定义的字段名(占位符),真实使用时替换为你的实际字段即可,例如按due分组:

task where due group by due

分组查询的语义

group by是 Dataview 查询的顶层子句(与where、sort等并列),其效果是把结果按指定字段的值聚合为组。查询类型由首行关键字决定——TASK、TABLE、LIST、CALENDAR四选一(参见 src/query/parse.ts 对TABLE|LIST|TASK|CALENDAR的解析,以及 src/query/query.ts 中的QueryType定义)。task关键字不区分大小写,因此关联文档中用小写task书写同样有效。

分组后每组通常呈现为「组值 + 组内任务」的层级结构,适合按日期、状态、负责人等维度组织任务视图。参考同目录下的 Grouped Sorted Tasks.md,还可以在分组前先排序,保证组内顺序稳定:

task where p sort p asc group by p

与排序、筛选的组合

test-vault 中 Sorted Tasks.md(实际文件为 Sorted Tasks.md)展示了不含分组的排序写法,可作为对照:

task where p sort p asc

将annotated过滤与group by结合,即可得到「只统计带元数据注释的任务,并按字段分组」的查询:

task where annotated and due sort due asc group by due

六、annotated字段的典型使用场景

  • 审计未标注任务:列出所有不含任何元数据字段的任务,检查是否有遗漏的日期、负责人等注释:
    task where !annotated
  • 统计带注释任务:配合GROUP BY或聚合函数(如length)统计库中带元数据任务的数量与分布。
  • 联动 Emoji 简写:由于简写会映射为字段,task where annotated也能覆盖「使用 Tasks 风格 Emoji 日期」的笔记,实现两种注释风格的统一检索。

七、从源码理解:任务字段的生命周期

结合 src/data-import/markdown-file.ts 的解析逻辑(completed: rawElement.task == "X" || rawElement.task == "x")与 src/data-import/inline-field.ts 对completed/due/done等特殊 Emoji 字段的解析,可以看到完整链路:

  1. Markdown 文件被解析为列表项ListItem,任务状态字符写入task.completed等属性,行内字段写入fieldsMap;
  2. serialize时根据this.fields.size > 0生成annotated布尔值(src/data-model/markdown.ts);
  3. 查询引擎按where/group by子句对序列化后的任务对象求值并渲染。

因此annotated的判定完全取决于解析阶段字段收集的完备性:只要任务行存在任意内联字段或 Emoji 日期简写,fields.size即大于 0。这也解释了为何annotated与勾选状态(completed)相互独立——它们是两个维度上的布尔标志。

八、小结

  • annotated是任务级隐式布尔字段,语义为「任务文本是否含元数据字段」,源码实现为this.fields.size > 0(src/data-model/markdown.ts),可与completed、checked、due等字段自由组合筛选。
  • group by可按任意字段对 TASK 查询结果分组,与where、sort组合后可以构建「带注释任务」的维度化视图。
  • 关联文档 Annotated Tasks.md 是一个可直接放入自己 Vault 运行的示例;完整的任务字段语义可查阅 metadata-tasks.md,内联字段语法见 add-metadata.md,查询结构说明见 query-types.md 与 structure.md。

将task where annotated与group by结合使用,你可以轻松从任意规模的 Markdown 任务库中,提炼出「已标注元数据的任务」并按维度聚合,让任务管理真正数据化。

  • 前端
  • 知识管理
  • 数据分析

【免费下载链接】obsidian-dataview

A data index and query language over Markdown files, for https://obsidian.md/.

项目地址:https://gitcode.com/gh_mirrors/ob/obsidian-dataview
点击查看免费下载
上一篇:30行代码实现文本到图像的魔术:imagen-pytorch中T5文本嵌入核心技术解析
下一篇:Screenshot-to-code代码架构评审工具:自动化架构检查

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询