Skip to content

dataview 插件教程

Dataview 实战

Dataview 是 Obsidian 最强大的数据处理插件,本指南通过实际案例帮助你掌握其用法。

基础查询

LIST 查询

最简单的列表形式查询:

dataview
LIST
FROM "笔记文件夹"
WHERE file.mtime >= date(today) - dur(7 days)
SORT file.mtime DESC

参数说明:

  • LIST:以列表形式显示
  • FROM:数据来源(文件夹/标签)
  • WHERE:筛选条件
  • SORT:排序方式

TABLE 查询

表格形式展示更多字段:

dataview
TABLE
  file.ctime AS "创建时间",
  file.mtime AS "修改时间",
  author AS "作者",
  status AS "状态"
FROM "项目"
WHERE status = "进行中"
SORT file.mtime DESC

任务查询

查询所有未完成任务:

dataview
TASK
FROM "任务"
WHERE !completed

常用查询示例

最近修改的笔记

dataview
TABLE
  file.mtime AS "修改时间",
  file.folder AS "位置"
FROM ""
WHERE file.mtime >= date(today) - dur(7 days)
SORT file.mtime DESC
LIMIT 10

按标签分类

dataview
TABLE
  file.ctime AS "创建时间",
  tags AS "标签"
FROM "#读书笔记"
SORT file.ctime DESC

项目进度追踪

dataview
TABLE
  progress AS "进度",
  deadline AS "截止日期",
  status AS "状态"
FROM "项目"
WHERE status != "已完成"
SORT deadline ASC

书籍阅读清单

dataview
TABLE
  author AS "作者",
  rating AS "评分",
  status AS "阅读状态"
FROM "书籍"
WHERE type = "book"
SORT rating DESC

高级查询技巧

计算字段

使用表达式创建计算字段:

dataview
TABLE
  file.name AS "笔记名",
  length(file.content) AS "字数",
  round(length(file.content)/1000, 1) AS "千字"
FROM "文章"
SORT length(file.content) DESC

链接字段

展示和操作链接:

dataview
TABLE
  author AS "作者",
  link(file.link, "查看") AS "链接"
FROM "文章"

日期计算

计算日期相关值:

dataview
TABLE
  file.ctime AS "创建时间",
  date(today) - file.ctime AS "距今天数"
FROM "笔记"
WHERE file.ctime <= date(today) - dur(30 days)

分组显示

使用 GROUP BY 分组:

dataview
TABLE
  rows.file.name AS "笔记"
FROM "项目"
GROUP BY status

嵌套字段

访问嵌套的 YAML 字段:

yaml
---
meta:
  author: 张三
  info:
    created: 2024-01-01
    updated: 2024-01-15
---
dataview
TABLE
  meta.author AS "作者",
  meta.info.created AS "创建日期"
FROM ""
WHERE meta

DataviewJS

什么是 DataviewJS

DataviewJS 允许使用 JavaScript 编写更复杂的查询,提供完全的编程控制能力。适用于 DQL 无法满足的复杂场景。

DQL vs DataviewJS 对比:

维度DQL(声明式查询)DataviewJS(编程式查询)
学习难度⭐⭐⭐⭐⭐⭐
灵活性中等极高
适用场景简单查询、表格复杂逻辑、自定义渲染
性能较好取决于代码质量
调试难度较高

dv 对象常用 API

API用途示例
dv.pages(source)获取页面集合dv.pages('"笔记"')
dv.page(path)获取单个页面dv.page("项目/A")
dv.table(headers, rows)渲染表格dv.table(["名","值"], rows)
dv.list(items)渲染列表dv.list([1, 2, 3])
dv.header(level, text)渲染标题dv.header(2, "标题")
dv.paragraph(text)渲染段落dv.paragraph("文本")
dv.taskList(tasks)渲染任务列表dv.taskList(dv.pages().tasks)
dv.el(tag, text)渲染任意 HTMLdv.el("b", "加粗")
dv.fileLink(path)创建文件链接dv.fileLink("笔记名")
dv.date(str)解析日期dv.date("2024-01-15")
dv.duration(str)解析时间间隔dv.duration("7 days")

动态统计

dataviewjs
// 统计各标签的笔记数量
const tags = dv.pages()
  .flatMap(p => p.file.tags)
  .groupBy(t => t)
  .map(t => ({tag: t.key, count: t.rows.length}))
  .sort(t => t.count, 'desc');

dv.table(["标签", "笔记数"], tags.map(t => [t.tag, t.count]));

进度条

dataviewjs
// 显示项目进度条
const pages = dv.pages("#project");

for (let page of pages) {
  const progress = page.progress || 0;
  const bar = "█".repeat(Math.floor(progress/10)) + "░".repeat(10-Math.floor(progress/10));
  dv.paragraph(`**${page.file.name}**: ${bar} ${progress}%`);
}

最近活动

dataviewjs
// 最近 7 天的活动
const week = dv.pages()
  .where(p => p.file.mtime >= dv.date("today") - dur("7 days"))
  .sort(p => p.file.mtime, 'desc');

dv.table(
  ["日期", "笔记", "修改时间"],
  week.map(p => [
    p.file.mtime.toFormat("MM-dd"),
    p.file.link,
    p.file.mtime.toFormat("HH:mm")
  ])
);

随机笔记发现

dataviewjs
// 随机推荐 5 篇笔记,帮助发现遗忘的内容
const allPages = dv.pages().where(p => !p.file.path.startsWith("模板"));
const shuffled = allPages.sort(() => Math.random() - 0.5);
const selected = shuffled.limit(5);

dv.header(3, "🎲 随机发现");
dv.table(
  ["笔记", "创建时间", "修改时间"],
  selected.map(p => [
    p.file.link,
    p.file.ctime.toFormat("yyyy-MM-dd"),
    p.file.mtime.toFormat("yyyy-MM-dd")
  ])
);

笔记健康检查

dataviewjs
// 检查笔记健康状况:孤立笔记、空笔记、过旧笔记
const pages = dv.pages().where(p => !p.file.path.startsWith("模板"));

// 孤立笔记(没有入链也没有出链)
const orphaned = pages.where(p => p.file.inlinks.length === 0 && p.file.outlinks.length === 0);

// 空笔记(内容少于 100 字符)
const empty = pages.where(p => p.file.length < 100);

// 超过 90 天未更新
const stale = pages.where(p => p.file.mtime < dv.date("today") - dur("90 days"));

dv.header(3, "🏥 笔记健康报告");
dv.paragraph(`📄 总笔记数:${pages.length}`);
dv.paragraph(`🏝️ 孤立笔记:${orphaned.length} 篇`);
dv.paragraph(`📭 空笔记:${empty.length} 篇`);
dv.paragraph(`💤 超过90天未更新:${stale.length} 篇`);

if (orphaned.length > 0) {
  dv.header(4, "孤立笔记");
  dv.list(orphaned.limit(10).map(p => p.file.link));
}

日记热力图

dataviewjs
// 统计每日笔记数量,生成简易热力图
const dailyNotes = dv.pages('"Daily"');
const dateCount = {};

for (let note of dailyNotes) {
  const date = note.file.name; // 假设文件名是日期格式
  dateCount[date] = (dateCount[date] || 0) + 1;
}

const maxCount = Math.max(...Object.values(dateCount), 1);
let heatmap = "";

for (let [date, count] of Object.entries(dateCount).sort()) {
  const intensity = Math.round((count / maxCount) * 4);
  const blocks = ["⬜", "🟨", "🟧", "🟥", "🟪"];
  heatmap += `${blocks[intensity]} ${date}: ${count} 篇\n`;
}

dv.paragraph(heatmap || "暂无日记数据");

自定义格式化输出

dataviewjs
// 生成格式化的周报
const today = dv.date("today");
const weekStart = today.minus(dur(`${today.weekday - 1} days`));

const weekPages = dv.pages()
  .where(p => p.file.ctime >= weekStart)
  .sort(p => p.file.ctime, 'desc');

dv.header(2, `📅 周报 ${weekStart.toFormat("MM-dd")} ~ ${today.toFormat("MM-dd")}`);
dv.paragraph(`本周新增笔记:${weekPages.length} 篇`);

// 按文件夹分组
const grouped = weekPages.groupBy(p => p.file.folder);
for (let group of grouped) {
  dv.header(3, `${group.key || "根目录"} (${group.rows.length})`);
  dv.list(group.rows.map(p => p.file.link));
}

条件渲染

dataviewjs
// 根据条件显示不同内容
const overdue = dv.pages("#task")
  .where(p => p.due && dv.date(p.due) < dv.date("today") && !p.completed);

if (overdue.length > 0) {
  dv.header(3, `⚠️ 逾期任务 (${overdue.length})`);
  dv.table(
    ["任务", "截止日期", "逾期天数"],
    overdue.map(p => [
      p.file.link,
      p.due,
      Math.floor(dv.date("today") - dv.date(p.due))
    ])
  );
} else {
  dv.paragraph("✅ 没有逾期任务!");
}

实战案例

每周回顾

dataview
TABLE
  choice(completed, "✅", "⬜") AS "状态",
  task AS "任务"
FROM "日记"
WHERE file.ctime >= date(today) - dur(7 days)

阅读统计

dataviewjs
// 本月阅读统计
const books = dv.pages("#书籍")
  .where(p => p.read_date && p.read_date.month === dv.date("today").month);

dv.paragraph(`📚 本月已读: ${books.length} 本`);

dv.table(
  ["书名", "作者", "评分"],
  books.map(b => [b.file.link, b.author, "⭐".repeat(b.rating || 0)])
);

任务看板

dataviewjs
// 简易看板
const tasks = {
  "待办": dv.pages().where(p => p.status === "todo"),
  "进行中": dv.pages().where(p => p.status === "doing"),
  "已完成": dv.pages().where(p => p.status === "done")
};

for (let [status, pages] of Object.entries(tasks)) {
  dv.header(3, `${status} (${pages.length})`);
  dv.list(pages.map(p => p.file.link));
}

知识图谱统计

dataviewjs
// 统计笔记关联
const notes = dv.pages();
const links = notes.flatMap(p => p.file.inlinks);

const mostLinked = links
  .groupBy(l => l.path)
  .map(g => ({note: g.key, count: g.rows.length}))
  .sort(l => l.count, 'desc')
  .limit(10);

dv.table(["笔记", "被引用次数"], mostLinked.map(l => [dv.fileLink(l.note), l.count]));

性能优化

限制结果

使用 LIMIT 提高性能:

dataview
TABLE file.name
FROM ""
LIMIT 100

避免全局搜索

指定具体文件夹:

dataview
-- 推荐
FROM "特定文件夹"

-- 避免全局搜索
FROM ""

索引字段

在 frontmatter 中定义索引字段:

yaml
---
tags: [项目, 重要]
status: 进行中
priority: 
---

常见问题

查询不显示

  • 检查 YAML 格式是否正确
  • 确认字段名称拼写无误
  • 查看 Obsidian 控制台错误

中文排序问题

使用自定义排序:

dataviewjs
dv.pages("笔记")
  .sort(p => p.file.name, 'asc', 'zh-CN')

日期格式化

dataviewjs
// 格式化日期
dv.date("2024-01-15").toFormat("yyyy年MM月dd日")

提示

Dataview 的强大在于可以动态展示笔记数据,建议从简单查询开始,逐步学习高级功能!

INFO

结合 Templater 插件使用,可以实现更强大的自动化工作流!

高级查询案例

本文将深入介绍 Dataview 的高级用法,通过实战案例帮助你掌握数据查询技巧。

基础回顾

Dataview 简介

Dataview 是一个强大的数据查询插件,可以将你的笔记变成数据库:

yaml
核心功能:
  - 数据查询:从笔记中提取信息
  - 数据展示:表格、列表、任务视图
  - 数据操作:过滤、排序、分组
  - 实时更新:自动同步数据变化

基本语法

查询类型

dataview
// 列表视图
LIST
FROM "folder"

// 表格视图
TABLE column1, column2
FROM "folder"

// 任务视图
TASK
FROM "folder"

// 日历视图
CALENDAR file.cday
FROM "folder"

数据源

dataview
// 按文件夹
FROM "Projects"

// 按标签
FROM #tag

// 按链接
FROM [[笔记名称]]

// 组合条件
FROM "Projects" OR #work

// 排除条件
FROM -"Templates"

进阶查询案例

案例 1:项目进度追踪

场景:追踪多个项目的进度和状态

数据结构

markdown
---
project: 项目名称
status: planning/active/completed/on-hold
priority: high/medium/low
start_date: 2024-01-01
due_date: 2024-06-30
progress: 60
---

查询:活跃项目概览

dataview
TABLE 
  project as "项目名称",
  status as "状态",
  priority as "优先级",
  progress as "进度",
  due_date as "截止日期",
  choice(
    due_date < date(today), 
    "🔴 已逾期",
    choice(
      due_date < date(today) + dur(7 days),
      "🟡 即将到期",
      "🟢 进行中"
    )
  ) as "状态标识"
FROM "01-Projects"
WHERE status = "active"
SORT priority ASC, due_date ASC

查询:项目进度统计

dataview
TABLE WITHOUT ID
  choice(
    status = "active", "🟢 进行中",
    choice(
      status = "completed", "✅ 已完成",
      choice(
        status = "planning", "📋 规划中",
        "⏸️ 暂停"
      )
    )
  ) as "状态",
  length(rows) as "项目数",
  default(round(sum(rows.progress) / length(rows), 1), 0) + "%" as "平均进度"
FROM "01-Projects"
GROUP BY status

查询:本周到期项目

dataview
TABLE 
  project as "项目",
  due_date as "截止日期",
  progress as "当前进度",
  due_date - date(today) as "剩余天数"
FROM "01-Projects"
WHERE status = "active" AND due_date <= date(today) + dur(7 days)
SORT due_date ASC

案例 2:阅读管理

场景:管理书籍阅读进度和笔记

数据结构

markdown
---
title: 书名
type: book
author: 作者
status: to-read/reading/done
rating: 0-5
start_date: 2024-01-01
finish_date: 2024-02-01
pages: 300
current_page: 150
tags: [book, fiction]
---

查询:阅读进度看板

dataview
TABLE 
  title as "书名",
  author as "作者",
  status as "状态",
  choice(
    status = "done", 
    "✅ 已完成",
    choice(
      status = "reading",
      round(current_page / pages * 100, 1) + "%",
      "📚 待读"
    )
  ) as "进度",
  rating as "评分"
FROM #book
SORT choice(
  status = "reading", 0,
  choice(status = "to-read", 1, 2)
) ASC, rating DESC

查询:本月阅读统计

dataview
TABLE WITHOUT ID
  length(filter(rows, (r) => r.status = "done")) as "已完成",
  length(filter(rows, (r) => r.status = "reading")) as "阅读中",
  length(filter(rows, (r) => r.status = "to-read")) as "待读",
  default(round(sum(filter(rows, (r) => r.status = "done").rating) / length(filter(rows, (r) => r.status = "done")), 2), 0) as "平均评分"
FROM #book
WHERE finish_date.month = date(today).month

查询:高分书籍推荐

dataview
LIST
FROM #book
WHERE rating >= 4 AND status = "done"
SORT rating DESC
LIMIT 10

查询:作者作品统计

dataview
TABLE WITHOUT ID
  author as "作者",
  length(rows) as "作品数",
  round(sum(rows.rating) / length(rows), 2) as "平均评分",
  join(limit(sort(map(rows, (r) => r.title), (a, b) => a < b), 3), ", ") as "代表作品"
FROM #book
WHERE status = "done"
GROUP BY author
SORT length(rows) DESC
LIMIT 10

案例 3:任务管理

场景:管理个人任务和待办事项

数据结构

markdown
---
created: 2024-01-01
due: 2024-01-15
completed: false
priority: high/medium/low
tags: [task, work]
---

# 任务标题

## 任务详情

- [ ] 子任务 1
- [x] 子任务 2
- [ ] 子任务 3

查询:今日待办

dataview
TASK
FROM "Tasks" OR "01-Projects"
WHERE !completed AND due = date(today)
SORT priority ASC

查询:本周任务概览

dataview
TABLE 
  file.link as "任务",
  due as "截止日期",
  priority as "优先级",
  choice(
    due < date(today), 
    "🔴 逾期",
    choice(
      due = date(today), 
      "🟡 今天",
      "🟢 即将到期"
    )
  ) as "状态"
FROM "Tasks"
WHERE !completed AND due >= date(today) - dur(1 day) AND due <= date(today) + dur(7 days)
SORT due ASC, priority ASC

查询:任务完成率统计

dataview
TABLE WITHOUT ID
  choice(
    priority = "high", "🔴 高优先级",
    choice(
      priority = "medium", "🟡 中优先级",
      "🟢 低优先级"
    )
  ) as "优先级",
  length(filter(rows, (r) => r.completed = true)) as "已完成",
  length(filter(rows, (r) => r.completed = false)) as "未完成",
  round(length(filter(rows, (r) => r.completed = true)) / length(rows) * 100, 1) + "%" as "完成率"
FROM "Tasks"
WHERE file.cday >= date(today) - dur(30 days)
GROUP BY priority

查询:逾期任务提醒

dataview
TASK
FROM "Tasks"
WHERE !completed AND due < date(today)
SORT due ASC

案例 4:笔记统计分析

场景:分析知识库的整体情况

查询:笔记增长趋势

dataview
TABLE WITHOUT ID
  file.cday as "创建日期",
  length(rows) as "新增笔记数"
FROM ""
WHERE file.cday >= date(today) - dur(30 days)
GROUP BY file.cday
SORT file.cday DESC

查询:活跃度统计

dataview
TABLE WITHOUT ID
  "本周" as "时间段",
  length(filter(dv.pages(""), (p) => p.file.cday >= date(today) - dur(7 days))) as "新增笔记",
  length(filter(dv.pages(""), (p) => p.file.mday >= date(today) - dur(7 days))) as "更新笔记",
  length(filter(dv.pages(""), (p) => p.file.cday = date(today))) as "今日新增"
FROM ""
LIMIT 1

查询:笔记类型分布

dataview
TABLE WITHOUT ID
  choice(
    type = "project", "📁 项目",
    choice(
      type = "book", "📚 书籍",
      choice(
        type = "article", "📝 文章",
        choice(
          type = "note", "📋 笔记",
          "📄 其他"
        )
      )
    )
  ) as "类型",
  length(rows) as "数量",
  round(length(rows) / length(dv.pages("")) * 100, 1) + "%" as "占比"
FROM ""
WHERE type
GROUP BY type
SORT length(rows) DESC

查询:标签使用统计

dataview
TABLE WITHOUT ID
  file.tags as "标签",
  length(rows) as "使用次数"
FROM ""
WHERE length(file.tags) > 0
GROUP BY file.tags
SORT length(rows) DESC
LIMIT 20

查询:孤立笔记检测

dataview
TABLE 
  file.link as "笔记",
  length(file.inlinks) as "被引用次数",
  length(file.outlinks) as "引用次数"
FROM ""
WHERE length(file.inlinks) = 0 AND length(file.outlinks) = 0
SORT file.ctime DESC
LIMIT 20

案例 5:学习进度管理

场景:追踪学习课程和知识点

数据结构

markdown
---
course: 课程名称
topic: 主题
status: not-started/learning/completed
difficulty: beginner/intermediate/advanced
hours: 5
progress: 80
tags: [learning, course]
---

# 知识点标题

## 学习笔记

## 练习题

查询:学习进度看板

dataview
TABLE 
  course as "课程",
  topic as "主题",
  status as "状态",
  progress as "进度",
  hours as "学时"
FROM "Learning"
WHERE status != "completed"
SORT course ASC, progress DESC

查询:课程完成统计

dataview
TABLE WITHOUT ID
  course as "课程",
  length(rows) as "知识点总数",
  length(filter(rows, (r) => r.status = "completed")) as "已完成",
  round(
    length(filter(rows, (r) => r.status = "completed")) / length(rows) * 100, 1
  ) + "%" as "完成率",
  sum(rows.hours) as "总学时"
FROM "Learning"
GROUP BY course
SORT length(rows) DESC

查询:难度分布

dataview
TABLE WITHOUT ID
  choice(
    difficulty = "beginner", "🔰 入门",
    choice(
      difficulty = "intermediate", "⭐ 进阶",
      "🚀 高级"
    )
  ) as "难度",
  length(rows) as "知识点数",
  length(filter(rows, (r) => r.status = "completed")) as "已完成"
FROM "Learning"
GROUP BY difficulty

查询:学习时间统计

dataview
TABLE WITHOUT ID
  sum(rows.hours) as "总学时",
  default(sum(filter(rows, (r) => r.status = "completed").hours), 0) as "已学完",
  default(sum(filter(rows, (r) => r.status = "learning").hours), 0) as "学习中",
  default(sum(filter(rows, (r) => r.status = "not-started").hours), 0) as "未开始"
FROM "Learning"

案例 6:会议记录管理

场景:管理会议记录和待办事项

数据结构

markdown
---
date: 2024-01-15
type: meeting
project: 项目名称
attendees: [张三, 李四]
---

# 会议记录

## 会议主题

## 待办事项

- [ ] 任务 1 - @张三
- [ ] 任务 2 - @李四

查询:近期会议记录

dataview
TABLE 
  date as "日期",
  project as "项目",
  join(attendees, ", ") as "参会人员"
FROM "Meetings"
WHERE date >= date(today) - dur(30 days)
SORT date DESC
LIMIT 10

查询:项目会议统计

dataview
TABLE WITHOUT ID
  project as "项目",
  length(rows) as "会议次数",
  join(limit(sort(map(rows, (r) => r.date), (a, b) => a > b), 3), ", ") as "最近会议"
FROM "Meetings"
GROUP BY project
SORT length(rows) DESC

查询:会议待办追踪

dataview
TASK
FROM "Meetings"
WHERE !completed
SORT file.link ASC

案例 7:健康习惯追踪

场景:追踪每日健康习惯

数据结构

markdown
---
date: 2024-01-01
type: daily-habits
sleep: 7
exercise: true
meditation: true
reading: true
water: 8
mood: good
---

# 习惯记录

## 今日习惯

- [x] 晨起运动
- [x] 阅读 30 分钟
- [x] 冥想 10 分钟

查询:本周习惯完成率

dataview
TABLE WITHOUT ID
  "晨起运动" as "习惯",
  round(sum(filter(rows, (r) => r.exercise = true)) / length(rows) * 100, 1) + "%" as "完成率"
FROM "Habits"
WHERE date >= date(today) - dur(7 days)
GROUP BY true

UNION

TABLE WITHOUT ID
  "冥想" as "习惯",
  round(sum(filter(rows, (r) => r.meditation = true)) / length(rows) * 100, 1) + "%" as "完成率"
FROM "Habits"
WHERE date >= date(today) - dur(7 days)
GROUP BY true

UNION

TABLE WITHOUT ID
  "阅读" as "习惯",
  round(sum(filter(rows, (r) => r.reading = true)) / length(rows) * 100, 1) + "%" as "完成率"
FROM "Habits"
WHERE date >= date(today) - dur(7 days)
GROUP BY true

查询:睡眠质量统计

dataview
TABLE WITHOUT ID
  avg(rows.sleep) as "平均睡眠时长",
  max(rows.sleep) as "最长睡眠",
  min(rows.sleep) as "最短睡眠"
FROM "Habits"
WHERE date >= date(today) - dur(30 days)

查询:心情分布

dataview
TABLE WITHOUT ID
  choice(
    mood = "good", "😊 很好",
    choice(
      mood = "normal", "😐 一般",
      "😔 不好"
    )
  ) as "心情",
  length(rows) as "天数",
  round(length(rows) / sum(map(filter(dv.pages("Habits"), (p) => p.date >= date(today) - dur(30 days)), (r) => 1)) * 100, 1) + "%" as "占比"
FROM "Habits"
WHERE date >= date(today) - dur(30 days)
GROUP BY mood
SORT length(rows) DESC

案例 8:内容创作管理

场景:管理博客文章创作流程

数据结构

markdown
---
title: 文章标题
status: idea/draft/review/published
category: 分类
published_date: 
word_count: 0
views: 0
tags: [blog, topic]
---

# 文章标题

## 大纲

## 内容

## 发布检查
- [ ] 标题优化
- [ ] SEO 检查
- [ ] 图片优化

查询:文章创作看板

dataview
TABLE 
  title as "标题",
  status as "状态",
  word_count as "字数",
  choice(
    status = "published", 
    "✅ 已发布",
    choice(
      status = "review",
      "📝 审核中",
      choice(
        status = "draft",
        "✏️ 草稿",
        "💡 想法"
      )
    )
  ) as "状态标识"
FROM "Blog"
SORT choice(
  status = "idea", 0,
  choice(status = "draft", 1,
  choice(status = "review", 2, 3))
) ASC, word_count DESC

查询:本月发布统计

dataview
TABLE WITHOUT ID
  length(filter(rows, (r) => r.status = "published")) as "已发布",
  length(filter(rows, (r) => r.status = "review")) as "审核中",
  length(filter(rows, (r) => r.status = "draft")) as "草稿",
  sum(filter(rows, (r) => r.status = "published").word_count) as "总字数"
FROM "Blog"
WHERE published_date.month = date(today).month

查询:热门文章排行

dataview
TABLE 
  title as "文章",
  views as "浏览量",
  word_count as "字数",
  published_date as "发布日期"
FROM "Blog"
WHERE status = "published"
SORT views DESC
LIMIT 10

查询:分类统计

dataview
TABLE WITHOUT ID
  category as "分类",
  length(rows) as "文章数",
  sum(rows.word_count) as "总字数",
  sum(rows.views) as "总浏览"
FROM "Blog"
WHERE status = "published"
GROUP BY category
SORT sum(rows.views) DESC

高级技巧

技巧 1:内联查询

在文本中直接插入查询

markdown
我今天有 `= length(filter(dv.pages("Tasks"), (t) => !t.completed AND t.due = date(today)))` 个待办任务。

本周新增笔记:`= length(filter(dv.pages(""), (p) => p.file.cday >= date(today) - dur(7 days)))` 篇。

当前项目进度:`= default(dv.page("Projects/当前项目").progress, 0) %`

技巧 2:条件渲染

根据条件显示不同内容

dataview
TABLE 
  title as "标题",
  choice(
    progress >= 80, "🚀 接近完成",
    choice(
      progress >= 50, "💪 进展顺利",
      choice(
        progress >= 20, "🐌 刚刚开始",
        "💤 尚未开始"
      )
    )
  ) as "进度状态"
FROM "Projects"

技巧 3:数据计算

复杂的数据计算

dataview
TABLE WITHOUT ID
  project as "项目",
  start_date as "开始日期",
  due_date as "截止日期",
  due_date - date(today) as "剩余天数",
  round((due_date - start_date).days, 0) as "总天数",
  round(progress * (due_date - start_date).days / 100, 0) as "已用天数",
  choice(
    (due_date - start_date).days - round(progress * (due_date - start_date).days / 100, 0) < 0,
    "⚠️ 可能延期",
    "✅ 进度正常"
  ) as "风险提示"
FROM "Projects"
WHERE status = "active"

技巧 4:多表联合

使用 UNION 合并多个查询

dataview
TABLE WITHOUT ID
  "项目笔记" as "类型", length(rows) as "数量"
FROM "Projects"
GROUP BY true

UNION

TABLE WITHOUT ID
  "学习笔记" as "类型", length(rows) as "数量"
FROM "Learning"
GROUP BY true

UNION

TABLE WITHOUT ID
  "会议记录" as "类型", length(rows) as "数量"
FROM "Meetings"
GROUP BY true

技巧 5:自定义函数

在 DataviewJS 中使用自定义函数

dataviewjs
// 自定义统计函数
function getStats(pages) {
  let total = pages.length;
  let completed = pages.where(p => p.status === "completed").length;
  let percent = total > 0 ? Math.round(completed / total * 100) : 0;
  return { total, completed, percent };
}

// 查询项目统计
let projects = dv.pages("01-Projects");
let stats = getStats(projects);

dv.paragraph(`
📊 **项目统计**
- 总项目数:${stats.total}
- 已完成:${stats.completed}
- 完成率:${stats.percent}%
`);

技巧 6:动态仪表板

创建自动更新的仪表板

dataviewjs
// 获取数据
let pages = dv.pages("");
let today = dv.date("today");

// 计算统计数据
let stats = {
  total: pages.length,
  todayNew: pages.where(p => p.file.cday.equals(today)).length,
  weekNew: pages.where(p => p.file.cday >= today.minus({days: 7})).length,
  monthNew: pages.where(p => p.file.cday >= today.minus({days: 30})).length
};

// 显示统计卡片
dv.paragraph(`
# 📊 知识库统计

<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;">

<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; color: white; text-align: center;">
  <div style="font-size: 32px; font-weight: bold;">${stats.total}</div>
  <div>总笔记数</div>
</div>

<div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); padding: 20px; border-radius: 10px; color: white; text-align: center;">
  <div style="font-size: 32px; font-weight: bold;">${stats.todayNew}</div>
  <div>今日新增</div>
</div>

<div style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); padding: 20px; border-radius: 10px; color: white; text-align: center;">
  <div style="font-size: 32px; font-weight: bold;">${stats.weekNew}</div>
  <div>本周新增</div>
</div>

<div style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); padding: 20px; border-radius: 10px; color: white; text-align: center;">
  <div style="font-size: 32px; font-weight: bold;">${stats.monthNew}</div>
  <div>本月新增</div>
</div>

</div>
`);

性能优化

优化建议

1. 限制查询范围

dataview
// ❌ 不推荐:查询所有笔记
FROM ""

// ✅ 推荐:限定文件夹
FROM "Projects"

// ✅ 推荐:限定标签
FROM #project

2. 使用索引字段

dataview
// ✅ 使用 frontmatter 字段
WHERE status = "active"

// ✅ 使用文件属性
WHERE file.cday >= date(today) - dur(7 days)

3. 避免复杂计算

dataview
// ❌ 不推荐:复杂嵌套
TABLE (
  length(filter(...))
) as "计算"

// ✅ 推荐:简化查询
TABLE status, progress
WHERE status = "active"

4. 分页查询

dataview
// 使用 LIMIT 限制结果数量
TABLE title, date
FROM "Blog"
SORT date DESC
LIMIT 10

5. 缓存查询结果

dataviewjs
// 使用变量缓存查询结果
let allPages = dv.pages("");

// 多次使用同一查询
let projects = allPages.where(p => p.type === "project");
let tasks = allPages.where(p => p.type === "task");

常见问题

Q1: 查询不显示结果?

yaml
检查清单:
  1. 数据源是否存在
     - 文件夹名称是否正确
     - 标签是否存在
  
  2. Frontmatter 格式是否正确
     - YAML 语法是否正确
     - 字段名是否拼写正确
  
  3. 查询条件是否匹配
     - 条件是否过于严格
     - 是否有数据满足条件
  
  4. 插件是否启用
     - Dataview 是否已安装启用
     - 是否有语法错误

Q2: 如何调试查询?

dataviewjs
// 调试方法:输出原始数据
let pages = dv.pages("Projects");
console.log(pages); // 在控制台查看

// 检查字段
dv.paragraph(`
字段列表:${pages.keys().join(", ")}
笔记数量:${pages.length}
第一条:${pages.first().file.link}
`);

Q3: 查询速度慢怎么办?

yaml
优化方法:
  1. 减少查询范围
     - 使用 FROM 限定
     - 添加 WHERE 条件
  
  2. 简化查询
     - 减少计算字段
     - 避免嵌套查询
  
  3. 使用索引
     - 在 frontmatter 中定义字段
     - 使用内置属性
  
  4. 异步加载
     - 分批查询
     - 延迟加载

参考资源


下一步