第5章:Dataview 动态查询

本章结构:先理解 Dataview 的查询模型与三种用法 → 再写 DQL / DataviewJS。
前提第4章:Templater 已完成,至少 1 本书Books/(否则查询为空是正常的)。
预计时间:概念 15 分钟 + 实操 40 分钟
复制提示:文中示例代码块语言标为 dql / js(便于网站发布)。在 Obsidian 里粘贴后,请把 dql 改回 dataviewjs 改回 dataviewjs


1. Dataview 是什么

Dataview 是 Obsidian 社区插件,把 vault 里的 Markdown 笔记当作数据库来查询:

换个更直觉的理解方式:想象你在 Excel 里有一张表,每一行是一本书,列是书名、作者、评分、标签。Dataview 就是这张表的查询工具——你可以问它「显示所有待读的书」「按评分从高到低排」「只显示文学类且评分 ≥ 8 的」。不同之处在于,这张表的每一行都是一篇独立的 Markdown 文件。

它不会改笔记,只读取已有 frontmatter。
所以 Templater 负责统一字段,Dataview 负责展示「待读有哪些」「评分 ≥8 的书」。


2. 核心功能一览

功能 说明
DQL Dataview Query Language,类 SQL;Obsidian 里代码块语言用 dataview(本站示例用 dql
DataviewJS Obsidian 里代码块语言用 dataviewjs(本站示例用 js
行内查询 段落内用反引号包裹「= 表达式」(详见 3.7 节)
LIST / TABLE / TASK 三种常见输出
FROM / WHERE / SORT 筛选文件夹、条件、排序
自动刷新 改 frontmatter 后视图更新(有时需 Force refresh)

3. 三种用法对比

用法 适合 难度
DQL LIST/TABLE 书单、待读、简单筛选 ⭐ 本教程重点
DataviewJS 标签统计、复杂逻辑 ⭐⭐ 需开 JS
行内 显示「书库共 N 本」 ⭐ 单行

设置里需开启:Enable Dataview;用 JS 时再开 Enable JavaScript Queries


4. 在本系列中的角色

flowchart LR
  TP[Templater 写入 YAML] --> B[Books/*.md]
  B --> DV[Dataview 查询块]
  DV --> L[LIST 待读]
  DV --> T[TABLE 已读]

字段名必须与 Books.md 模板一致(ISBNtagsrating…)。


5. 跟着做:启用 Dataview

  1. 设置 → Dataview
  2. 确认 Enable Dataview 已开
  3. 若本章要用 DataviewJS(3.5 节):开启 Enable JavaScript Queries
  4. 在本章阅读模式下直接编辑练习区即可

3.3 前置:Books 的 YAML 约定

Tools/Templater/Books.md 对齐,Dataview 依赖这些字段:

字段 类型 示例
title 文本 白色绵羊里的黑色绵羊
author 文本 作者名
ISBN 文本 9787532184439
rating 数字 7.6(豆瓣评分)
myRating 数字或空 你的评分
tags 列表 [文学] 或含 待读
addDate 日期 2026-06-28

跟着做:打开 Books/白色绵羊里的黑色绵羊.md,对照上表检查字段是否存在。


3.4 跟着做:待读书单(DQL LIST)

在本章笔记或任意 MOC 中粘贴:

## 待读

```dql
LIST
FROM "Books"
WHERE contains(tags, "待读")
SORT addDate DESC
```

切换到阅读模式(或 Live Preview 中渲染 Dataview)。

验证

语法说明

子句 含义
FROM "Books" 只查 Books/ 文件夹
WHERE contains(tags, "待读") 标签列表包含「待读」
SORT addDate DESC 按入库日期倒序

关于数据类型的一个提醒:Dataview 会根据 frontmatter 的值推断类型。比如 rating: 7.6 被识别为数字,你可以用 rating >= 8 来筛选;addDate: 2026-06-28 被识别为日期,所以 SORT addDate DESC 按时间排序是生效的。但如果你的 frontmatter 里某个字段有时是数字有时是字符串(比如 rating: "7.6" 带引号),Dataview 可能无法正确比较——这是写 frontmatter 时需要注意保持一致性的原因。


3.5 跟着做:已读书籍表格(DQL TABLE)

## 已读(非待读)

```dql
TABLE author AS "作者", rating AS "豆瓣", myRating AS "我的", addDate AS "入库"
FROM "Books"
WHERE !contains(tags, "待读")
SORT rating DESC
```

验证:表格有表头;rating 高的排在前面。

扩展:只显示评分 ≥ 8 的书:

TABLE author, rating
FROM "Books"
WHERE rating >= 8
SORT rating DESC

3.6 跟着做:按标签统计(DataviewJS)

当 DQL 不够灵活时,用 DataviewJS(需开启 JavaScript Queries):

## 各标签书本数(不含「待读」)

```js
const pages = dv.pages('"Books"');
const tagCounts = {};
for (const p of pages) {
  const tags = p.tags ?? [];
  for (const t of tags) {
    if (t === "待读") continue;
    tagCounts[t] = (tagCounts[t] || 0) + 1;
  }
}
const rows = Object.entries(tagCounts)
  .sort((a, b) => b[1] - a[1])
  .map(([tag, n]) => [tag, n]);
dv.table(["标签", "本数"], rows);
```

验证:输出两列表格,例如 文学 | 3

代码逻辑

  1. dv.pages('"Books"') — 取文件夹下所有页
  2. 遍历每页的 tags 数组
  3. 跳过 待读,累加计数
  4. dv.table 渲染

3.7 跟着做:行内查询(Inline)

在普通段落里写动态数字,无需单独代码块:

书架共有 [美元等号] dv.pages('"Books"').length 本书。

(Obsidian 里用反引号包裹「美元 + 等号」前缀即可渲染。)

验证:阅读模式下显示实际数量,例如在 Books/ 有 4 本则显示 4。

再试一条:待读数量

待读 [美元等号] dv.pages('"Books"').where(p => p.tags && p.tags.includes("待读")).length 本。

3.8 跟着做:带封面列的 TABLE(可选)

若 frontmatter 有 cover 且文件存在:

```dql
TABLE author AS "作者", rating AS "评分", cover AS "封面"
FROM "Books"
WHERE contains(tags, "待读")
SORT addDate DESC
LIMIT 10
```

封面列可能显示为路径文本;在 Obsidian 主题下部分版本可渲染缩略图。以你当前 Dataview 版本为准。


3.9 与 Templater 的衔接

阶段 负责插件
导入时写入 tagsISBNrating Templater + Douban
阅读时自动列出「待读」 Dataview
tags 从待读 → 文学 你手动或 Claudian 批量改
列表自动更新 Dataview 无需改查询

字段改名时:先改 Books.md 模板 → 再批量改旧笔记 → 最后改 Dataview 查询里的字段名。


3.10 性能与维护


3.11 本章练习

在本章末尾完成:


3.12 常见坑

现象 原因 处理
查询块显示代码不渲染 没开 Dataview;或编辑模式没切到 Live Preview/阅读模式 检查插件是否启用;尝试切到阅读模式
结果为空 FROM 路径写错了;或者字段名和 frontmatter 不一致 先用 FROM "Books";确认 YAML 字段名跟查询里写的一模一样(大小写敏感)
contains(tags, "待读") 查不到 tags 被写成了字符串而不是列表 检查 YAML:tags: 文学 不对,应该是 tags:\n - 文学(带短横线的列表格式)
DataviewJS 报错 没开 JavaScript 执行权限 去设置里打开 Enable JavaScript Queries

更多片段见 附录 §B。


← 上一章 蒸馏术 主页 下一章 →
第4章:Templater 第6章:Navigator