[Obsidian/可视化/插件] Obsidian Dataview 插件: 把 Markdown 笔记变成可查询数据库 —— DQL 与 JavaScript 双引擎驱动的动态视图插件

0 序言

  • 最近刷到世界知名的AI博主 Karpathy 的 LLM Wiki 项目,阅读了这篇文章,其中提到了 Obsidian 的 Dataview 插件,为此了解了解。

LLM Wiki 是由前 Tesla AI总监、OpenAI创始成员Andrej Karpathy 于2026年4月提出的一种个人知识库构建与管理范式、规约、愿景、最佳实践。
[知识库/知识管理] LLM Wiki:面向个人与小型团队的、LLM 驱动的编译型结构化知识库 | 个人知识库构建与管理范式 - 博客园/数据知音
Astro-Han/karpathy-llm-wiki(主流开源实现,Agent Skills 标准实现,社区最活跃)
karpathy/llm-wiki.md - github LLM Wiki 的发起 Repo:

image

  • 内容提要:Obsidian DataView 插件的核心特性
  • 数据库化:将 Vault 中所有笔记的元数据(YAML + 行内字段 + 隐式字段)构建为实时索引
  • 双引擎:DQL 声明式查询(覆盖 90% 常规需求)+ DataviewJS 编程 API(无限扩展)
  • 动态视图:TABLE / LIST / TASK / CALENDAR 四种输出,结果实时刷新、支持交互

1 概述: Obsidian Dataview 插件

插件效果

image

产品介绍

  • Obsidian Dataview 是一款将 Obsidian 知识库(Vault)视为可查询数据库的第三方社区插件。它通过解析 Markdown 文件中的元数据(YAML Frontmatter 与行内字段),构建实时索引,并提供类 SQL 的查询语言(DQL)和完整的 JavaScript API,让用户能够对笔记数据进行筛选、排序、分组、聚合与可视化展示。

  • 产品定位:Obsidian 生态中最流行、功能最强大的结构化数据查询与动态视图插件

  • 诞生背景:Obsidian 原生仅支持静态 Markdown 笔记与简单搜索,用户缺乏对笔记元数据进行结构化查询、自动汇总和动态仪表盘的能力。Dataview 填补了这一空白,使笔记从"静态文档"升级为"可查询的数据记录"

  • 解决的核心问题

    • 跨笔记的元数据自动汇总(如读书清单、项目进度、任务看板)
    • 基于条件的动态筛选与排序(无需手动维护列表)
    • 任务的集中管理与状态追踪
    • 自定义仪表盘与数据可视化
  • URL

发展历程

时间 版本 关键事件
2021-01-31 首次发布 正式登陆 Obsidian 社区插件市场,作者 Michael Brenan(blacksmithgu)
2021 年 0.3.x ~ 0.4.x 快速迭代期,确立 DQL 语法、四种查询类型(TABLE/LIST/TASK/CALENDAR)、DataviewJS API
2022 年 0.4.19 ~ 0.4.26 新增 CALENDAR 查询视图、任务子任务支持、多行任务、时区支持、性能优化
2023 年 0.5.x 引入 IndexedDB 元数据缓存(0.5.19),大幅提升大型知识库启动速度;持续优化 Live Preview 渲染
2024 年 0.5.4x ~ 0.5.6x 维护期,重点修复 Live Preview 列表渲染、文档完善、新增辅助函数
2025-03-16 0.5.68(稳定版) 大量文档修复、Live Preview 列表渲染修复、新增/文档化函数
2025-04-07 0.5.70(Beta) 尝试修复 #2557 问题,后续维护节奏放缓

维护状态说明:截至 2026 年 8 月,Dataview 的稳定版仍为 0.5.68,Beta 版停留在 0.5.70。

原作者 blacksmithgu 逐步减少投入,社区贡献者(如 holroy)参与维护。
尽管更新频率降低,但插件功能已高度成熟,社区生态(教程、示例、衍生插件)极为丰富,仍是 Obsidian 数据查询领域的事实标准

核心功能 *

  1. 4种查询模式

    • DQL(Dataview Query Language):流水线式、类 SQL 的声明式查询语言,覆盖 90% 常规需求
    • Inline DQL:在 Markdown 正文中嵌入单行 DQL 表达式,预览模式下自动求值(如 `= this.file.name`
    • DataviewJS:完整的 JavaScript API,可访问索引数据、执行复杂逻辑、自定义渲染,是高级用户的"逃生舱"
    • Inline JS:在正文中嵌入单行 JavaScript 表达式(如 `$= dv.current().file.mtime`
  2. 4种查询输出类型

    • TABLE表格视图,每行一条结果(1行即1个文件),每列一个字段
    • LIST无序列表视图,可附带一个字段
    • TASK交互式任务列表,支持勾选完成、按文件分组
    • CALENDAR日历视图,以圆点标记匹配日期的笔记
  3. 元数据采集

    • 解析 YAML Frontmatter(文件顶部 --- 包裹的键值对)
    • 解析 行内字段Key:: Value 语法,Dataview 独创)
    • 自动生成 隐式字段(文件名、创建/修改时间、标签、入链/出链、任务列表等,统一挂载在 file.* 下)
  4. 丰富的数据命令

    • FROM:按文件夹、标签、链接限定数据源
    • WHERE:按字段条件过滤
    • SORT:按字段排序(升序/降序)
    • GROUP BY:按字段分组
    • LIMIT:限制结果数量
    • FLATTEN:将多值字段拆分为多行
  5. 内置函数库:字符串处理、日期运算、数学计算、类型转换、列表操作等数十个函数

  6. 自定义视图(Custom Views):通过 dv.view() 加载独立的 JS 视图文件,实现复杂 UI 组件复用

核心优势

  • 零侵入、纯文本:所有元数据存储在标准 Markdown 的 YAML Frontmatter 或行内字段中,不依赖专有格式,数据完全属于用户,可被任何文本编辑器读取
  • 实时动态更新:索引在后台自动维护,笔记修改后查询结果即时刷新,无需手动刷新或重新生成
  • 学习曲线平缓:DQL 语法接近 SQL,有数据库基础的用户可快速上手;即使零基础,通过 TABLE ... FROM ... 的简单模式也能立即产出结果
  • JavaScript 无限扩展:DataviewJS 提供完整编程能力,理论上可实现任意复杂的数据处理与自定义渲染,这是多数竞品不具备的
  • 社区生态庞大:作为 Obsidian 下载量最高的插件之一,拥有海量教程、示例仓库、论坛讨论和衍生插件(如 Dataview Query Builder 可视化工具)
  • 与 Obsidian 深度集成:原生支持 Wiki 链接、标签、任务、书签等 Obsidian 核心概念,查询结果中的链接可直接点击跳转

主要短板

  • 维护节奏放缓:原作者投入减少,稳定版自 2025 年 3 月后未更新,部分长期存在的 Issue(如 #2557)未完全修复
  • 大型知识库性能问题:在超过数千篇笔记的 Vault 中,全库扫描查询可能导致卡顿;虽有 IndexedDB 缓存缓解,但未加 FROM 限定的查询仍可能较慢
  • DQL 表达能力有限:复杂逻辑(如多表关联、子查询、窗口函数)无法用 DQL 表达,必须 resort 到 DataviewJS,提高了高级用法的门槛
  • 无原生编辑能力:查询结果默认是只读视图,不能直接在表格中编辑元数据(需配合其他插件或 DataviewJS 实现)
  • 行内字段语法非标准Key:: Value 是 Dataview 独创语法,在其他 Markdown 编辑器中会原样显示为文本,存在一定的锁定风险
  • 调试体验一般:DQL 报错信息不够友好,语法错误时定位困难;DataviewJS 调试需依赖 Obsidian 开发者控制台

局限性

  • 仅支持 Markdown 文件:无法查询 PDF、图片、Office 文档等非 Markdown 附件的内容元数据
  • 无持久化存储:查询结果是动态计算的,不会写回文件;如需保存快照需手动导出
  • 不支持跨 Vault 查询:索引范围限定在当前打开的知识库内
  • 移动端性能受限:在手机/平板等移动设备上,复杂 DataviewJS 查询可能明显卡顿
  • 安全风险:DataviewJS 可执行任意 JavaScript,若从不可信来源复制脚本存在安全隐患(插件设置中可禁用 JS 查询)

适用场景

  • 读书笔记管理:自动汇总所有书籍的书名、作者、评分、阅读状态,按评分排序或按类型分组
  • 项目管理仪表盘:集中展示所有进行中项目的进度、截止日期、负责人,自动过滤已完成项目
  • 任务追踪:跨笔记收集所有未完成任务,按优先级/截止日期排序,支持直接勾选完成
  • 日记/周报自动生成:从每日笔记中提取关键数据(完成任务数、学习时长等),自动生成周报
  • 内容资产盘点:统计知识库中各类型笔记数量、标签分布、最近修改的文件
  • 会议纪要管理:按日期/项目/参会人筛选会议记录,自动生成待办事项汇总
  • 学习进度追踪:跟踪课程/书籍的章节完成情况,计算整体进度百分比

同类竞品

竞品 类型 核心特点 与 Dataview 的差异
Obsidian Bases 官方核心插件(2025 年推出) Notion 风格的数据库视图,支持表格/卡片布局,可视化筛选排序,可直接编辑属性 官方原生、零代码、可编辑,但无查询语言和 JS API,复杂逻辑能力弱;目前视图类型较少
Projects 第三方插件 基于文件夹的项目管理,支持表格/看板/日历/日历时间线等多视图 更侧重项目管理场景,UI 更友好,但查询灵活性不如 Dataview
DB Folder 第三方插件 将文件夹变为 Notion 式数据库,支持多种列类型、公式、关联 可直接在视图中编辑数据,适合结构化数据管理,但缺乏全局查询能力
Notion Bases for Obsidian 第三方插件 7 种视图、18 种列类型、公式、关联、汇总、子任务,纯 Markdown 存储 功能最接近 Notion,视图丰富,但社区成熟度和生态远不如 Dataview
DataCards 第三方插件 卡片式数据展示,支持看板视图 侧重可视化卡片展示,查询能力较弱

选型建议:如果你需要灵活的全局查询、复杂的数据处理、自定义仪表盘,Dataview 仍是首选;如果你更看重可视化操作、直接编辑、Notion 式体验,可以尝试 Obsidian Bases 或 Notion Bases for Obsidian。两者并非互斥,很多用户同时使用 Dataview(用于复杂查询)和 Bases(用于日常数据编辑)。

发展趋势

  • 官方 Bases 的竞争压力:Obsidian 官方在 2025 年推出核心插件 Bases,提供了可视化的数据库视图,对 Dataview 的基础使用场景(表格展示、筛选排序)形成直接竞争。

未来普通用户可能更多转向 Bases,而 Dataview 将更聚焦于需要编程能力的高级用户

  • 维护模式转变:从原作者主导开发转向社区维护模式,功能迭代放缓但稳定性持续提升
  • 与 AI 工作流结合:越来越多用户将 Dataview 与 AI 插件(如 Smart Connections、Copilot)结合,用 Dataview 结构化数据作为 AI 的上下文输入
  • 衍生工具生态:出现了 Dataview Query Builder(可视化 DQL 生成器)、Dataview to Properties(元数据迁移工具)等周边工具
  • 元数据标准化趋势:Obsidian 原生 Properties(属性)功能的完善,使用户更多使用标准 YAML Frontmatter 而非 Dataview 行内字段,这有利于数据的可移植性

总结:Dataview 已进入成熟稳定期,虽然面临官方 Bases 的竞争,但其不可替代的 JavaScript API 和庞大社区生态使其在可预见的未来仍将是 Obsidian 高级数据查询的首选工具

2 工作原理与架构

概念术语

术语 说明
Vault(知识库) Obsidian 管理的根文件夹,包含所有 Markdown 笔记和附件。Dataview 的索引范围限定在当前 Vault 内
Metadata(元数据) 描述笔记的数据,包括用户自定义的字段和 Dataview 自动生成的隐式字段
Frontmatter(前置元数据) Markdown 文件顶部用 --- 包裹的 YAML 格式键值对,是 Obsidian 标准的元数据存储方式
Inline Field(行内字段) Dataview 独创的元数据语法,格式为 Key:: Value,可写在笔记正文中任意位置
Implicit Field(隐式字段) Dataview 自动为每个文件生成的元数据,如文件名、创建时间、标签、链接等,统一通过 file.* 访问
DQL(Dataview Query Language) Dataview 的声明式查询语言,语法类似 SQL,采用流水线式的子句组合
DataviewJS Dataview 的 JavaScript API,在 dataviewjs 代码块中执行,通过全局 dv 对象访问索引和渲染工具
Query Type(查询类型) 决定查询输出格式的关键字,包括 TABLE、LIST、TASK、CALENDAR 四种
Data Command(数据命令) 查询中用于限定、过滤、排序、分组的子句,包括 FROM、WHERE、SORT、GROUP BY、LIMIT、FLATTEN
Source(数据源) FROM 子句的参数,用于限定查询范围,可以是文件夹路径、标签、链接表达式
Index(索引) Dataview 在后台维护的元数据数据库,存储所有文件的解析结果,基于 IndexedDB 持久化缓存
Custom View(自定义视图) 通过 dv.view() 加载的独立 JS 文件,可封装复杂的渲染逻辑并在多处复用

架构与运行原理

Dataview 的整体架构可分为数据采集层、索引存储层、查询引擎层、渲染展示层四个部分:

graph TB subgraph 数据采集层 A[Markdown 文件] --> B[YAML Frontmatter 解析器] A --> C[行内字段解析器] A --> D[隐式字段生成器] end subgraph 索引存储层 B --> E[元数据索引引擎] C --> E D --> E E --> F[(IndexedDB 缓存)] E --> G[内存索引] end subgraph 查询引擎层 H[DQL 解析器<br/>parsimmon] --> I[查询执行器] J[DataviewJS API] --> I I --> G end subgraph 渲染展示层 I --> K[Preact UI 组件] K --> L[TABLE 视图] K --> M[LIST 视图] K --> N[TASK 视图] K --> O[CALENDAR 视图] end P[Obsidian 事件总线] --> E P --> K

2.2.1 数据采集层

Dataview 在 Obsidian 启动时和文件变更时,对 Vault 中的每个 Markdown 文件进行解析:

  • YAML Frontmatter 解析:读取文件顶部 --- 之间的 YAML 内容,将每个键值对转化为字段。支持嵌套对象(通过 . 访问)和数组
  • 行内字段解析:扫描正文,匹配 Key:: Value 模式的行内字段。支持三种写法:
    • 独立行:Key:: Value
    • 方括号包裹:[Key:: Value](可隐藏键名显示)
    • 圆括号包裹:(Key:: Value)(键名和值都隐藏,仅用于数据存储)
  • 隐式字段生成:为每个文件自动生成 file.* 系列字段,包括文件名、路径、创建/修改时间、标签列表、入链/出链列表、任务列表、列表元素等

2.2.2 索引存储层

  • 元数据索引引擎:核心组件,负责调度文件解析、维护索引一致性。通过监听 Obsidian 的文件创建、修改、删除、重命名事件,实时更新索引
  • 内存索引:所有已解析文件的元数据存储在内存中,供查询引擎快速访问。Vault 打开时全量构建,之后增量更新
  • IndexedDB 缓存:自 0.5.19 版本引入,将解析后的元数据持久化到浏览器的 IndexedDB 中。下次启动时优先从缓存加载,再增量校验变更,大幅缩短大型 Vault 的启动时间

2.2.3 查询引擎层

  • DQL 解析器:基于 parsimmon(解析器组合子库)构建,将 DQL 文本解析为抽象语法树(AST)。DQL 采用流水线式设计,每个数据命令(FROM/WHERE/SORT 等)依次对数据集进行变换
  • 查询执行器:遍历 AST,从索引中获取数据,依次应用过滤、排序、分组、扁平化、限制等操作,最终生成结果集
  • DataviewJS API:提供 dv 全局对象,直接暴露索引数据(如 dv.pages()dv.page())和渲染方法(如 dv.table()dv.list()dv.taskList()),用户可编写任意 JavaScript 逻辑处理数据

2.2.4 渲染展示层

  • 基于 Preact(轻量级 React 替代库)构建 UI 组件
  • 四种查询类型对应四种渲染组件:TABLE(表格)、LIST(列表)、TASK(交互式任务列表)、CALENDAR(日历)
  • 渲染结果嵌入 Obsidian 的阅读模式和 Live Preview 模式中
  • TASK 视图支持交互:点击复选框可直接修改源文件中的任务状态
  • 支持 Obsidian 主题样式,可通过 CSS 自定义外观

2.2.5 关键技术依赖

依赖库 用途
luxon 日期与时间处理,提供 DateTimeDuration 等类型
parsimmon 解析器组合子库,用于构建 DQL 语法解析器
preact 轻量级 React 替代,用于构建查询结果的 UI 组件
localforage 客户端存储封装,IndexedDB 缓存的底层依赖
@codemirror/* 代码编辑器集成,为 dataview/dataviewjs 代码块提供语法高亮
papaparse CSV 数据处理(辅助功能)

3 使用指南

3.1 安装部署

3.1.1 通过 Obsidian 社区插件市场安装(推荐)

  1. 打开 Obsidian → 设置(Settings)→ 第三方插件(Community plugins)
  2. 关闭"安全模式"(Safe mode)(首次使用第三方插件时)
  3. 点击"浏览"(Browse),搜索 Dataview
  4. 点击"安装"(Install),安装完成后点击"启用"(Enable)

3.1.2 手动安装(适用于无法访问插件市场的环境)

  1. GitHub Releases 下载最新版本的三个文件:main.jsmanifest.jsonstyles.css
  2. 在 Vault 的插件目录下创建文件夹:<Vault根目录>/.obsidian/plugins/dataview/
  3. 将三个文件放入该文件夹
  4. 重启 Obsidian,在 设置 → 第三方插件 中启用 Dataview

3.1.3 关键设置项

安装后进入 设置 → Dataview,可配置以下选项:

设置项 说明 推荐值
Enable JavaScript Queries 是否允许执行 dataviewjs 代码块 高级用户开启;安全敏感场景可关闭
Enable Inline JavaScript Queries 是否允许执行行内 JS 表达式($= ... 同上
Enable Inline Field Highlighting 是否高亮显示行内字段(Key:: Value 开启,便于识别元数据
Inline Field Prefix 行内字段前缀字符 默认 ::
Wikilink Target Columns 表格中哪些列自动渲染为 Wiki 链接 默认开启
Recursive Tag/Subtag Matching 标签是否递归匹配子标签(如 #book 匹配 #book/fiction 开启

元数据标注(数据准备)(必读)

在使用查询之前,需要先为笔记添加元数据。Dataview 支持三种元数据来源。

3.2.1 YAML Frontmatter

在文件顶部用 --- 包裹的 YAML 键值对:

---
title: "深入理解计算机系统"
author: "Randal E. Bryant"
rating: 9
status: "reading"
tags:
  - book
  - computer-science
publish-date: 2021-03-01
pages: 1120
---

支持的数据类型

  • 文本(字符串):author: "Randal E. Bryant"
  • 数字:rating: 9pages: 1120
  • 布尔值:reviewed: true
  • 日期:publish-date: 2021-03-01(ISO 格式自动识别为日期类型)
  • 数组/列表:tags: [book, computer-science] 或多行格式
  • 嵌套对象:metadata: { rating: 9, reviewed: false }(通过 metadata.rating 访问)

3.2.2 行内字段(Inline Fields)

在笔记正文中任意位置使用 Key:: Value 语法:

# 读书笔记

**书名**:: 深入理解计算机系统
**作者**:: Randal E. Bryant
**评分**:: 9
**状态**:: reading

这是一本经典的计算机系统教材。

也可以在行内使用:我最近在读 [书名:: 深入理解计算机系统],感觉 [难度:: 较高]。

如果想完全隐藏字段:(完成度:: 60%)

3种行内字段写法对比

写法 渲染效果 适用场景
Key:: Value 显示为 "Key:: Value"(带高亮) 需要在正文中同时展示键和值
[Key:: Value] 仅显示 "Value"(键隐藏) 需要展示值但不显示键名
(Key:: Value) 键和值都不显示(完全隐藏) 仅用于存储数据,不希望在阅读时看到

3.2.3 隐式字段(Implicit Fields)

  • Dataview 自动为每个文件生成,无需手动标注,通过 file.* 访问:
字段 类型 说明
file.name 文本 文件名(不含扩展名)
file.folder 文本 所在文件夹路径
file.path 文本 完整文件路径(含文件名)
file.ext 文本 文件扩展名,通常为 md
file.link 链接 指向该文件的 Wiki 链接
file.size 数字 文件大小(字节)
file.ctime 日期时间 文件创建时间
file.cday 日期 文件创建日期
file.mtime 日期时间 文件最后修改时间
file.mday 日期 文件最后修改日期
file.tags 列表 所有标签(含子标签展开,如 #a/b 展开为 #a, #a/b
file.etags 列表 所有显式标签(不展开子标签)
file.inlinks 列表 所有指向本文件的链接(入链)
file.outlinks 列表 本文件中所有向外的链接(出链)
file.aliases 列表 文件的别名(来自 Frontmatter 的 aliases
file.tasks 列表 文件中所有任务(- [ ] / - [x]
file.lists 列表 文件中所有列表元素(含任务)
file.day 日期 仅当文件名含日期(如 2026-08-22)或有 date 字段时可用
file.starred 布尔 是否被 Obsidian 书签插件收藏

DQL 查询语法详解

3.3.1 查询的基本结构 *

每个 DQL 查询遵循以下流水线结构:

<QUERY-TYPE> <字段列表>
FROM <数据源>
<数据命令>
<数据命令>
...
  • QUERY-TYPE(必填):TABLE / LIST / TASK / CALENDAR 之一
  • FROM(可选):限定数据源,只能出现一次,且必须紧跟在 QUERY-TYPE 之后
  • 其他数据命令(可选,可多次、任意顺序):WHERE / SORT / GROUP BY / LIMIT / FLATTEN

3.3.2 查询类型(Query Type): TABLE / LIST / TASK / CALENDAR

TABLE — 表格视图

最常用的查询类型,以表格形式展示结果:

TABLE 字段1, 字段2 AS "别名", 计算表达式
FROM 数据源

示例

TABLE file.name AS "书名", author AS "作者", rating AS "评分", status AS "状态"
FROM "books" //目录 = "books"
WHERE rating >= 8
SORT rating DESC

无字段 TABLETABLE WITHOUT ID 可隐藏默认的第一列(文件链接列):

TABLE WITHOUT ID title AS "书名", rating AS "评分"
FROM #book //含有 book 的 tags 的文件

LIST — 列表视图

以无序列表形式展示匹配的文件,可附带一个字段:

LIST 字段
FROM 数据源

示例

LIST "评分:" + rating
FROM #book
WHERE status = "reading"
SORT rating DESC

TASK — 任务视图

以交互式任务列表展示,支持直接勾选完成:

TASK
FROM 数据源
WHERE 条件

示例

TASK
FROM #projects/active
WHERE !completed
GROUP BY file.link

TASK 查询的结果是任务项(对应源文件的- [] xxx text行)而非文件,因此 WHERE 中可直接使用任务的字段(如 completedduepriority),以及 file.* 来访问任务所在文件的元数据。

CALENDAR — 日历视图

简介

  • 月历形式展示,每个匹配的笔记在对应日期上显示一个圆点:
CALENDAR 日期字段
FROM 数据源
WHERE <过滤条件>
  • 与 TABLE/LIST/TASK 不同,CALENDAR 的日期字段是必填的—— 日历需要知道每条结果对应哪一天
  • 示例

以笔记的创建日期(file.cday)为坐标,将 Vault 中所有笔记渲染到月历上,有笔记的日期显示圆点。

CALENDAR file.cday
FROM "diaryDir"
SORT file.cday desc

检索逻辑(执行流程)

graph LR A[1. 数据源筛选<br/>FROM/WHERE] --> B[2. 提取日期字段<br/>每行取 date 字段值] B --> C[3. 按日期分组<br/>同一天的文件归为一组] C --> D[4. 渲染月历<br/>有文件的日期画圆点]
  • 逐步拆解
步骤 说明
① 筛选文件集合 先通过 FROM(文件夹 / 标签 / 链接)和 WHERE(字段条件)筛选出符合条件的笔记,与其他查询类型完全一致
② 提取日期字段 对筛选出的每篇笔记,读取 CALENDAR 关键字后指定的字段值。该值必须是日期类型(date),否则该条记录会被丢弃
③ 按日期分组 将所有笔记按日期值分组。同一天的多篇笔记归为同一组
④ 渲染月历 输出标准月历视图(月 / 周切换),有匹配笔记的日期显示圆点;同一天有多篇笔记时,圆点会堆叠显示(多个圆点纵向排列)

日期字段的来源x3种

  1. 隐式字段(最常用)
字段 含义
file.cday 文件创建日期
file.mday 文件最后修改日期
file.day 仅当文件名含日期(如 2026-08-22.md)或 Frontmatter 有 date 字段时可用
  1. 自定义 Frontmatter 日期字段
---
due: 2026-09-15
birthday: 1990-05-20
publish-date: 2026-08-01
---

对应的 dataview

CALENDAR due
FROM #task
WHERE !completed
  1. 计算 / 转换后的日期

如果日期存储为字符串,需用 date() 函数转换:

CALENDAR date(due_str)
FROM "projects"

也可以对日期做简单运算:

CALENDAR due - dur(7 days)
FROM #task

在截止日期前 7 天的位置显示提醒圆点。

关键注意事项

问题 说明
日期字段为 null 会怎样? 该条记录不会显示在日历上。建议加 WHERE 日期字段 过滤掉无日期的记录,虽然不加也能自动跳过,但显式写出更清晰
日期时间类型(DateTime)呢? 只取日期部分,时间部分被忽略。如 file.ctime(含时分秒)也可正常用于 CALENDAR
同一天多篇笔记怎么显示? 圆点会堆叠,纵向排列多个圆点。鼠标悬停可看到具体文件
能自定义圆点颜色吗? DQL 层面不支持,圆点颜色由当前 Obsidian 主题决定。如需自定义颜色,需用 DataviewJS 或 CSS 片段(.dataview-calendar-dot)
能显示多个日期字段吗? 不能,一个 CALENDAR 查询只能指定一个日期字段。如需同时看创建日和修改日,需写两个独立的 CALENDAR 代码块
点击圆点会怎样? 点击日期或圆点会跳转到对应笔记(如果当天只有一篇)或显示该天的文件列表
支持周视图吗? 支持,日历视图右上角可切换月 / 周视图
性能如何? CALENDAR 本身渲染开销不大,但如果 FROM 不限定范围、全库扫描,在大 Vault 中仍可能较慢。建议始终加 FROM 限定

3.3.3 FROM — 数据源限定

FROM 用于限定查询的文件范围,支持以下数据源类型:

数据源类型 语法 说明
文件夹 FROM "路径" 查询指定文件夹及其子文件夹下的所有文件
标签 FROM #标签 查询包含指定标签的文件
入链 FROM [[文件名]] 查询链接到指定文件的所有文件
出链 FROM outgoing([[文件名]]) 查询指定文件中链接到的所有文件

组合表达式:支持 ANDORNOT 和括号组合:

-- 标签或文件夹
FROM #book OR "books"

-- 同时满足标签和文件夹
FROM #book AND "books/fiction"

-- 排除某文件夹
FROM #book AND -"books/archived"

-- 复杂组合
FROM (#assignment AND "30 School") OR ("30 School/32 Homeworks" AND outgoing([[School Dashboard]]))

文件夹路径前加 - 表示排除,如 FROM -"templates" 排除模板文件夹。

3.3.4 WHERE — 条件过滤

WHERE 用于按字段条件过滤结果,支持比较运算符和逻辑运算符:

比较运算符=!=<><=>=

逻辑运算符ANDORNOT(或 !

示例

TABLE title, rating, status
FROM #book
WHERE rating >= 8 AND status = "completed"
LIST
WHERE due AND due < date(today)
TABLE title, author
FROM #book
WHERE contains(tags, "科幻") OR contains(author, "刘慈欣")

常用过滤模式

  • 字段存在性检查:WHERE rating(rating 字段存在且非空)
  • 字段不存在:WHERE !ratingWHERE rating = null
  • 文本包含:WHERE contains(title, "算法")
  • 列表包含:WHERE contains(tags, "#book")
  • 日期比较:WHERE due > date(today)
  • 正则匹配:WHERE regexmatch("^A", title)

3.3.5 SORT — 排序

SORT 字段 [ASC|DESC]
  • ASC:升序(默认)
  • DESC:降序

示例

TABLE title, rating, file.mtime
FROM #book
SORT rating DESC, file.mtime ASC

支持多字段排序,先按第一个字段排序,相同则按第二个字段排序。

3.3.6 GROUP BY — 分组

将结果按指定字段分组,每组生成一行。分组后,组内数据通过 rows 关键字访问:

TABLE rows.file.link AS "书籍", length(rows) AS "数量"
FROM #book
GROUP BY genre

示例

TABLE length(rows) AS "书籍数量", average(rows.rating) AS "平均评分"
FROM #book
GROUP BY genre
SORT length(rows) DESC

3.3.7 LIMIT — 限制结果数

LIMIT 数字

示例

TABLE title, rating
FROM #book
SORT rating DESC
LIMIT 10

3.3.8 FLATTEN — 扁平化

将多值字段(如数组、列表)拆分为多行,每行一个值:

FLATTEN 字段 AS 别名

示例

TABLE file.name AS "文件", L AS "列表项"
FROM "dailys"
FLATTEN file.lists AS L
WHERE contains(L.text, "重要")
TABLE file.name AS "书名", tag AS "标签"
FROM #book
FLATTEN tags AS tag

3.3.9 表达式与函数

运算符

类别 运算符 说明
算术 + - * / % 加减乘除取模
比较 = != < > <= >= 比较运算
逻辑 AND OR NOT / ! 逻辑运算
字符串 + 字符串拼接
列表 + 列表合并

常用函数

字符串函数

函数 说明 示例
lower(x) 转小写 lower("Hello") = "hello"
upper(x) 转大写 upper("Hello") = "HELLO"
length(x) 字符串/列表长度 length("abc") = 3
contains(haystack, needle) 是否包含 contains("hello", "ell") = true
startswith(s, prefix) 是否以...开头 startswith("abc", "a") = true
endswith(s, suffix) 是否以...结尾 endswith("abc", "c") = true
replace(s, pattern, replacement) 替换 replace("a-b", "-", "_") = "a_b"
regexmatch(pattern, s) 正则匹配 regexmatch("^\\d+$", "123") = true
trim(s) 去除首尾空白 trim(" abc ") = "abc"
substring(s, start, end) 截取子串 substring("abcde", 1, 3) = "bc"

日期函数

函数 说明 示例
date(any) 转换为日期 date("2026-08-22")
date(today) 今天日期 date(today)
date(tomorrow) 明天日期 date(tomorrow)
date(yesterday) 昨天日期 date(yesterday)
duration(any) 转换为时长 duration("7 days")
day(x) 获取日期中的日 day(date("2026-08-22")) = 22
month(x) 获取月份 month(date("2026-08-22")) = 8
year(x) 获取年份 year(date("2026-08-22")) = 2026
hour(x) 获取小时 用于日期时间类型

数学函数

函数 说明
round(x) 四舍五入
floor(x) 向下取整
ceil(x) 向上取整
min(a, b) / max(a, b) 最小/最大值
sum(list) 列表求和
average(list) 列表平均值
min(list) / max(list) 列表最小/最大值

类型与其他函数

函数 说明
typeof(x) 返回值的类型(string/number/boolean/date/link/list/object/null)
number(x) 转换为数字
string(x) 转换为字符串
link(path, [display]) 创建链接
embed(link) 创建嵌入链接(![[...]]
elink(url, [display]) 创建外部链接
nonnull(list) 过滤列表中的 null 值
object(k1, v1, ...) 创建对象
array(...) 创建数组

3.3.10 行内 DQL 查询(Inline DQL)

在 Markdown 正文中使用反引号包裹,以 = 开头:

当前笔记名称:`= this.file.name`
当前笔记创建于:`= this.file.cday`
本书评分:`= this.rating`
距离截止日期还有:`= this.due - date(today)`
  • this 关键字引用当前笔记的元数据
  • 行内查询在阅读模式/Live Preview 下自动求值并显示结果
  • 支持所有 DQL 表达式和函数

DataviewJS 进阶用法

3.4.1 基本结构

dataviewjs 代码块中编写 JavaScript,通过全局 dv 对象访问 API:

// 获取所有带 #book 标签的页面
const books = dv.pages("#book");

// 渲染表格
dv.table(
  ["书名", "作者", "评分"],
  books
    .where(b => b.rating >= 8)
    .sort(b => b.rating, "desc")
    .map(b => [b.file.link, b.author, b.rating])
);

3.4.2 核心 API

数据获取

API 说明
dv.pages(source?) 获取匹配数据源的所有页面(返回 Page 数组),如 dv.pages("#book")dv.pages('"folder"')
dv.page(path) 获取指定路径的单个页面
dv.current() 获取当前代码块所在的页面

渲染方法

API 说明
dv.table(headers, values) 渲染表格,headers 为列名数组,values 为二维数组
dv.list(elements) 渲染无序列表
dv.taskList(tasks, groupByFile?) 渲染交互式任务列表,groupByFile 默认为 true
dv.header(level, text) 渲染标题
dv.paragraph(text) 渲染段落
dv.el(tag, text, options?) 渲染自定义 HTML 元素
dv.view(path, input?) 加载并渲染自定义视图

工具方法

API 说明
dv.date(any) 解析为日期对象
dv.duration(any) 解析为时长对象
dv.array(value) 确保值为数组
dv.isLink(value) 判断是否为链接类型
dv.isDateTime(value) 判断是否为日期时间类型
dv.isDuration(value) 判断是否为时长类型

3.4.3 Page 对象的属性与方法

dv.pages() 返回的每个 Page 对象可直接访问元数据字段:

const page = dv.pages("#book").first();

// 自定义字段
page.title;
page.rating;
page.author;

// 隐式字段
page.file.name;
page.file.ctime;
page.file.tags;
page.file.tasks;
page.file.inlinks;

链式查询方法(类似 Lodash 的集合操作):

方法 说明
.where(predicate) 过滤
.sort(comparator, direction?) 排序,direction 为 "asc""desc"
.groupBy(selector) 分组,返回 { key, rows } 数组
.map(fn) 映射转换
.flatMap(fn) 扁平化映射
.limit(n) 限制数量
.slice(start, end?) 切片
.first() / .last() 获取首/末元素
.length 元素数量

3.4.4 实战示例

示例 1:带进度条的项目列表

const projects = dv.pages("#project").where(p => p.status === "active");

for (const project of projects) {
  const tasks = project.file.tasks;
  const completed = tasks.where(t => t.completed).length;
  const total = tasks.length;
  const percent = total > 0 ? Math.round((completed / total) * 100) : 0;

  dv.header(4, project.file.link);
  dv.el("div", `
    <div style="background:#e0e0e0;border-radius:4px;height:8px;margin:4px 0;">
      <div style="background:#4caf50;border-radius:4px;height:8px;width:${percent}%"></div>
    </div>
    <span style="font-size:0.85em;color:#666">${completed}/${total} 任务 (${percent}%)</span>
  `);
}

示例 2:按项目分组的未完成任务

const tasks = dv.pages("#project").file.tasks.where(t => !t.completed);
const grouped = tasks.groupBy(t => t.file.link);

for (const group of grouped) {
  dv.header(4, group.key);
  dv.taskList(group.rows, false);
}

示例 3:最近 30 天完成任务统计

const allTasks = dv.pages().file.tasks;
const completed = allTasks.where(t => {
  if (!t.completed) return false;
  // 任务完成时间(如果有 completion 字段)
  if (t.completion) {
    return t.completion > dv.date("today").minus({ days: 30 });
  }
  return false;
});

dv.header(3, `最近 30 天完成 ${completed.length} 个任务`);
dv.taskList(completed, true);

示例 4:标签分布统计

const allPages = dv.pages();
const tagCount = {};

for (const page of allPages) {
  for (const tag of page.file.tags) {
    tagCount[tag] = (tagCount[tag] || 0) + 1;
  }
}

const sorted = Object.entries(tagCount)
  .sort((a, b) => b[1] - a[1])
  .slice(0, 20);

dv.table(
  ["标签", "数量"],
  sorted.map(([tag, count]) => [tag, count])
);

3.4.5 行内 JS 查询

在正文中使用反引号包裹,以 $= 开头:

本笔记最后修改于 `$= dv.current().file.mtime`
本知识库共有 `$= dv.pages().length` 篇笔记
当前项目进度:`$= Math.round(dv.current().file.tasks.where(t => t.completed).length / dv.current().file.tasks.length * 100)`%

3.4.6 自定义视图(Custom Views)

将复杂的 DataviewJS 逻辑封装为独立文件,通过 dv.view() 复用:

  1. 在 Vault 中创建视图文件夹,如 views/project-progress/
  2. 在其中创建 view.js
// views/project-progress/view.js
const { project } = input;
const tasks = project.file.tasks;
const completed = tasks.where(t => t.completed).length;
const total = tasks.length;
const percent = total > 0 ? Math.round((completed / total) * 100) : 0;

dv.header(4, project.file.link);
dv.paragraph(`进度:${completed}/${total} (${percent}%)`);
  1. 在任意笔记中调用:
for (const project of dv.pages("#project")) {
  dv.view("views/project-progress", { project });
}

常用查询模板

3.5.1 读书笔记管理

TABLE file.name AS "书名", author AS "作者", rating AS "评分", status AS "阅读状态"
FROM #book
SORT rating DESC

3.5.2 今日待办

TASK
FROM "diary"
WHERE !completed AND (due = date(today) OR contains(text, "今天"))
SORT priority DESC

3.5.3 逾期任务

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

3.5.4 最近修改的笔记

TABLE file.mtime AS "修改时间", file.folder AS "位置"
FROM -"templates"
SORT file.mtime DESC
LIMIT 15

3.5.5 本月生日/纪念日

LIST birthday
FROM #contact
WHERE birthday AND month(birthday) = month(date(today))
SORT day(birthday) ASC

3.5.6 项目仪表盘(综合)

TABLE WITHOUT ID
  file.link AS "项目",
  status AS "状态",
  priority AS "优先级",
  due AS "截止日期",
  length(file.tasks.where(t => !t.completed)) AS "待办数"
FROM #project
WHERE status != "archived"
SORT priority DESC, due ASC

Z FAQ

Q: Dataview 查询不显示结果怎么办?

首先检查以下几点:

  1. 语法错误:确认代码块语言标记为 dataview(而非 dataviewjs),关键字拼写正确(TABLEFROMWHERE 等)
  2. 数据源路径FROM "文件夹路径" 中的路径是否正确,路径相对于 Vault 根目录,区分大小写
  3. 字段名WHERETABLE 中引用的字段名是否与 Frontmatter/行内字段中的键名完全一致(区分大小写)
  4. 字段类型:比较运算时确保字段类型一致,如日期字段需用 date() 转换后再比较
  5. 索引未更新:尝试重启 Obsidian 或在设置中触发"重新索引"(Reload Index)
  6. 查看控制台:按 Ctrl+Shift+I(Windows/Linux)或 Cmd+Opt+I(Mac)打开开发者工具,查看 Console 中的报错信息

Q: 行内字段 Key:: Value 不被识别怎么办?

  1. 确认在 Dataview 设置中开启了 Enable Inline Field Highlighting
  2. 行内字段的 :: 前后可以有空格,但 Key 部分不能包含冒号
  3. 如果行内字段在标题行(如 ## 标题 Key:: Value),可能不被解析,建议放在正文中
  4. 方括号写法 [Key:: Value] 和圆括号写法 (Key:: Value) 中的字段同样会被索引
  5. 如果字段值包含特殊字符(如 ::#[[]]),建议使用 YAML Frontmatter 存储

Q: 如何在查询结果中直接编辑数据?

Dataview 的 DQL 查询结果默认是只读的。如需直接编辑,有以下方案:

  1. 使用 Obsidian Bases:官方核心插件 Bases 支持在表格视图中直接编辑属性
  2. 使用 DB Folder 或 Notion Bases 插件:这些插件提供可编辑的数据库视图
  3. DataviewJS + 自定义 UI:通过 DataviewJS 编写自定义 HTML 表单,结合 Obsidian API 实现数据写回(难度较高)
  4. 点击链接跳转编辑:查询结果中的文件链接可点击跳转到源文件,在源文件中编辑 Frontmatter

Q: Dataview 和 Obsidian 官方 Bases 有什么区别?该选哪个?

维度 Dataview Obsidian Bases
性质 第三方社区插件 官方核心插件
查询方式 DQL 查询语言 + JavaScript API 可视化筛选/排序,无查询语言
可编辑性 只读(DQL) 可直接编辑属性
视图类型 TABLE/LIST/TASK/CALENDAR 表格/卡片(持续增加中)
复杂逻辑 支持(通过 JS) 不支持
学习成本 较高(需学 DQL/JS) 低(可视化操作)
全局查询 支持(跨文件夹/标签) 基于文件夹/属性,范围较固定

建议:日常简单的数据展示和编辑用 Bases,需要复杂查询、自定义仪表盘、跨库汇总时用 Dataview。两者可以共存。

Q: 大型知识库中 Dataview 查询很慢怎么办?

优化策略:

  1. 始终使用 FROM 限定范围:避免全库扫描,如 FROM "books"FROM #book
  2. 减少查询数量:一个页面中不要放置过多 dataview 代码块
  3. 避免复杂的 WHERE 计算:如在 WHERE 中使用正则、字符串处理等会降低性能
  4. 使用 LIMIT 限制结果数:不需要展示全部结果时加上 LIMIT
  5. 禁用不必要的隐式字段索引:在设置中可关闭部分索引功能(如任务索引、列表索引)
  6. 考虑拆分 Vault:如果笔记数量超过数万篇,可考虑按主题拆分为多个 Vault
  7. 使用 IndexedDB 缓存:确保 Dataview 版本 >= 0.5.19,缓存功能默认开启

Q: DataviewJS 安全吗?可以随意复制网上的脚本吗?

不安全。DataviewJS 可执行任意 JavaScript 代码,拥有访问 Obsidian API、文件系统(通过 Obsidian API)、网络请求等权限。从不可信来源复制脚本存在以下风险:

  • 窃取或篡改你的笔记数据
  • 发送数据到外部服务器
  • 执行恶意操作

安全建议

  1. 只从可信来源(官方文档、知名社区、自己理解的代码)复制脚本
  2. 使用前仔细阅读代码,理解每一行的作用
  3. 在 Dataview 设置中可关闭 Enable JavaScript Queries 来禁用所有 JS 查询
  4. 对于简单需求,优先使用 DQL 而非 DataviewJS

Q: 如何查询任务的子任务?

Dataview 支持任务的层级关系。在 TASK 查询中:

  • 每个任务对象有 children 属性,包含其子任务列表
  • t.completed 仅表示当前任务本身是否完成,不考虑子任务
  • 可通过 t.subtasks 访问所有后代任务
TASK
FROM #project
WHERE !completed AND length(children) > 0

在 DataviewJS 中:

const tasks = dv.pages().file.tasks;
const parentTasks = tasks.where(t => t.children.length > 0);
dv.taskList(parentTasks, true);

Q: 日期比较不生效怎么办?

常见原因和解决方案:

  1. 字段不是日期类型:如果 Frontmatter 中日期写为 due: "2026-08-22"(带引号),会被识别为字符串而非日期。应去掉引号:due: 2026-08-22
  2. 比较时需转换:如果字段确实是字符串,在查询中用 date(due) 转换后再比较:WHERE date(due) < date(today)
  3. 日期格式:确保日期为 ISO 格式 YYYY-MM-DD,其他格式可能无法被正确识别
  4. 行内字段日期:行内字段中的日期同样需要符合 ISO 格式,如 due:: 2026-08-22

Q: 如何在 Dataview 中使用 CSS 自定义样式?

Dataview 的查询结果会被特定的 CSS 类包裹,可通过自定义 CSS 片段(CSS Snippets)修改样式:

  1. 在 Vault 的 .obsidian/snippets/ 目录下创建 dataview-custom.css
  2. 添加样式规则,常用选择器:
    • .dataview — 所有 Dataview 结果的外层容器
    • .dataview.table-view-table — TABLE 视图的表格
    • .dataview.table-view-table th — 表头
    • .dataview.task-list-item — TASK 视图的任务项
    • .dataview.list-view-ul — LIST 视图的列表
  3. 在 Obsidian 设置 → 外观 → CSS 代码片段 中启用该片段

示例:

/* 表格斑马纹 */
.dataview.table-view-table tr:nth-child(even) {
  background-color: rgba(0, 0, 0, 0.05);
}

/* 表头加粗 */
.dataview.table-view-table th {
  font-weight: 700;
}

Q: 如何导出 Dataview 查询结果?

Dataview 结果是动态渲染的,不会自动保存为文件。导出方式:

  1. 复制粘贴:在阅读模式下选中查询结果,复制为 Markdown 表格或纯文本
  2. 截图:使用截图工具保存为图片
  3. DataviewJS 导出:编写脚本将结果写入文件(通过 Obsidian API 的 vault.create()
  4. 打印为 PDF:使用 Obsidian 的"导出为 PDF"功能,包含查询结果的页面会被导出
  5. 配合其他插件:如使用 "Advanced Tables" 等插件辅助表格处理

Y 推荐文献

X 参考文献

posted @ 2026-08-22 13:53  千千寰宇  阅读(3)  评论(0)    收藏  举报