dataview 插件教程
Dataview 实战
Dataview 是 Obsidian 最强大的数据处理插件,本指南通过实际案例帮助你掌握其用法。
基础查询
LIST 查询
最简单的列表形式查询:
LIST
FROM "笔记文件夹"
WHERE file.mtime >= date(today) - dur(7 days)
SORT file.mtime DESC参数说明:
LIST:以列表形式显示FROM:数据来源(文件夹/标签)WHERE:筛选条件SORT:排序方式
TABLE 查询
表格形式展示更多字段:
TABLE
file.ctime AS "创建时间",
file.mtime AS "修改时间",
author AS "作者",
status AS "状态"
FROM "项目"
WHERE status = "进行中"
SORT file.mtime DESC任务查询
查询所有未完成任务:
TASK
FROM "任务"
WHERE !completed常用查询示例
最近修改的笔记
TABLE
file.mtime AS "修改时间",
file.folder AS "位置"
FROM ""
WHERE file.mtime >= date(today) - dur(7 days)
SORT file.mtime DESC
LIMIT 10按标签分类
TABLE
file.ctime AS "创建时间",
tags AS "标签"
FROM "#读书笔记"
SORT file.ctime DESC项目进度追踪
TABLE
progress AS "进度",
deadline AS "截止日期",
status AS "状态"
FROM "项目"
WHERE status != "已完成"
SORT deadline ASC书籍阅读清单
TABLE
author AS "作者",
rating AS "评分",
status AS "阅读状态"
FROM "书籍"
WHERE type = "book"
SORT rating DESC高级查询技巧
计算字段
使用表达式创建计算字段:
TABLE
file.name AS "笔记名",
length(file.content) AS "字数",
round(length(file.content)/1000, 1) AS "千字"
FROM "文章"
SORT length(file.content) DESC链接字段
展示和操作链接:
TABLE
author AS "作者",
link(file.link, "查看") AS "链接"
FROM "文章"日期计算
计算日期相关值:
TABLE
file.ctime AS "创建时间",
date(today) - file.ctime AS "距今天数"
FROM "笔记"
WHERE file.ctime <= date(today) - dur(30 days)分组显示
使用 GROUP BY 分组:
TABLE
rows.file.name AS "笔记"
FROM "项目"
GROUP BY status嵌套字段
访问嵌套的 YAML 字段:
---
meta:
author: 张三
info:
created: 2024-01-01
updated: 2024-01-15
---TABLE
meta.author AS "作者",
meta.info.created AS "创建日期"
FROM ""
WHERE metaDataviewJS
什么是 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) | 渲染任意 HTML | dv.el("b", "加粗") |
dv.fileLink(path) | 创建文件链接 | dv.fileLink("笔记名") |
dv.date(str) | 解析日期 | dv.date("2024-01-15") |
dv.duration(str) | 解析时间间隔 | dv.duration("7 days") |
动态统计
// 统计各标签的笔记数量
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]));进度条
// 显示项目进度条
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}%`);
}最近活动
// 最近 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")
])
);随机笔记发现
// 随机推荐 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")
])
);笔记健康检查
// 检查笔记健康状况:孤立笔记、空笔记、过旧笔记
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));
}日记热力图
// 统计每日笔记数量,生成简易热力图
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 || "暂无日记数据");自定义格式化输出
// 生成格式化的周报
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));
}条件渲染
// 根据条件显示不同内容
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("✅ 没有逾期任务!");
}实战案例
每周回顾
TABLE
choice(completed, "✅", "⬜") AS "状态",
task AS "任务"
FROM "日记"
WHERE file.ctime >= date(today) - dur(7 days)阅读统计
// 本月阅读统计
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)])
);任务看板
// 简易看板
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));
}知识图谱统计
// 统计笔记关联
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 提高性能:
TABLE file.name
FROM ""
LIMIT 100避免全局搜索
指定具体文件夹:
-- 推荐
FROM "特定文件夹"
-- 避免全局搜索
FROM ""索引字段
在 frontmatter 中定义索引字段:
---
tags: [项目, 重要]
status: 进行中
priority: 高
---常见问题
查询不显示
- 检查 YAML 格式是否正确
- 确认字段名称拼写无误
- 查看 Obsidian 控制台错误
中文排序问题
使用自定义排序:
dv.pages("笔记")
.sort(p => p.file.name, 'asc', 'zh-CN')日期格式化
// 格式化日期
dv.date("2024-01-15").toFormat("yyyy年MM月dd日")提示
Dataview 的强大在于可以动态展示笔记数据,建议从简单查询开始,逐步学习高级功能!
INFO
结合 Templater 插件使用,可以实现更强大的自动化工作流!
高级查询案例
本文将深入介绍 Dataview 的高级用法,通过实战案例帮助你掌握数据查询技巧。
基础回顾
Dataview 简介
Dataview 是一个强大的数据查询插件,可以将你的笔记变成数据库:
核心功能:
- 数据查询:从笔记中提取信息
- 数据展示:表格、列表、任务视图
- 数据操作:过滤、排序、分组
- 实时更新:自动同步数据变化基本语法
查询类型:
// 列表视图
LIST
FROM "folder"
// 表格视图
TABLE column1, column2
FROM "folder"
// 任务视图
TASK
FROM "folder"
// 日历视图
CALENDAR file.cday
FROM "folder"数据源:
// 按文件夹
FROM "Projects"
// 按标签
FROM #tag
// 按链接
FROM [[笔记名称]]
// 组合条件
FROM "Projects" OR #work
// 排除条件
FROM -"Templates"进阶查询案例
案例 1:项目进度追踪
场景:追踪多个项目的进度和状态
数据结构:
---
project: 项目名称
status: planning/active/completed/on-hold
priority: high/medium/low
start_date: 2024-01-01
due_date: 2024-06-30
progress: 60
---查询:活跃项目概览
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查询:项目进度统计
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查询:本周到期项目
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:阅读管理
场景:管理书籍阅读进度和笔记
数据结构:
---
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]
---查询:阅读进度看板
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查询:本月阅读统计
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查询:高分书籍推荐
LIST
FROM #book
WHERE rating >= 4 AND status = "done"
SORT rating DESC
LIMIT 10查询:作者作品统计
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:任务管理
场景:管理个人任务和待办事项
数据结构:
---
created: 2024-01-01
due: 2024-01-15
completed: false
priority: high/medium/low
tags: [task, work]
---
# 任务标题
## 任务详情
- [ ] 子任务 1
- [x] 子任务 2
- [ ] 子任务 3查询:今日待办
TASK
FROM "Tasks" OR "01-Projects"
WHERE !completed AND due = date(today)
SORT priority ASC查询:本周任务概览
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查询:任务完成率统计
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查询:逾期任务提醒
TASK
FROM "Tasks"
WHERE !completed AND due < date(today)
SORT due ASC案例 4:笔记统计分析
场景:分析知识库的整体情况
查询:笔记增长趋势
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查询:活跃度统计
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查询:笔记类型分布
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查询:标签使用统计
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查询:孤立笔记检测
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:学习进度管理
场景:追踪学习课程和知识点
数据结构:
---
course: 课程名称
topic: 主题
status: not-started/learning/completed
difficulty: beginner/intermediate/advanced
hours: 5
progress: 80
tags: [learning, course]
---
# 知识点标题
## 学习笔记
## 练习题查询:学习进度看板
TABLE
course as "课程",
topic as "主题",
status as "状态",
progress as "进度",
hours as "学时"
FROM "Learning"
WHERE status != "completed"
SORT course ASC, progress DESC查询:课程完成统计
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查询:难度分布
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查询:学习时间统计
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:会议记录管理
场景:管理会议记录和待办事项
数据结构:
---
date: 2024-01-15
type: meeting
project: 项目名称
attendees: [张三, 李四]
---
# 会议记录
## 会议主题
## 待办事项
- [ ] 任务 1 - @张三
- [ ] 任务 2 - @李四查询:近期会议记录
TABLE
date as "日期",
project as "项目",
join(attendees, ", ") as "参会人员"
FROM "Meetings"
WHERE date >= date(today) - dur(30 days)
SORT date DESC
LIMIT 10查询:项目会议统计
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查询:会议待办追踪
TASK
FROM "Meetings"
WHERE !completed
SORT file.link ASC案例 7:健康习惯追踪
场景:追踪每日健康习惯
数据结构:
---
date: 2024-01-01
type: daily-habits
sleep: 7
exercise: true
meditation: true
reading: true
water: 8
mood: good
---
# 习惯记录
## 今日习惯
- [x] 晨起运动
- [x] 阅读 30 分钟
- [x] 冥想 10 分钟查询:本周习惯完成率
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查询:睡眠质量统计
TABLE WITHOUT ID
avg(rows.sleep) as "平均睡眠时长",
max(rows.sleep) as "最长睡眠",
min(rows.sleep) as "最短睡眠"
FROM "Habits"
WHERE date >= date(today) - dur(30 days)查询:心情分布
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:内容创作管理
场景:管理博客文章创作流程
数据结构:
---
title: 文章标题
status: idea/draft/review/published
category: 分类
published_date:
word_count: 0
views: 0
tags: [blog, topic]
---
# 文章标题
## 大纲
## 内容
## 发布检查
- [ ] 标题优化
- [ ] SEO 检查
- [ ] 图片优化查询:文章创作看板
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查询:本月发布统计
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查询:热门文章排行
TABLE
title as "文章",
views as "浏览量",
word_count as "字数",
published_date as "发布日期"
FROM "Blog"
WHERE status = "published"
SORT views DESC
LIMIT 10查询:分类统计
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:内联查询
在文本中直接插入查询:
我今天有 `= 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:条件渲染
根据条件显示不同内容:
TABLE
title as "标题",
choice(
progress >= 80, "🚀 接近完成",
choice(
progress >= 50, "💪 进展顺利",
choice(
progress >= 20, "🐌 刚刚开始",
"💤 尚未开始"
)
)
) as "进度状态"
FROM "Projects"技巧 3:数据计算
复杂的数据计算:
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 合并多个查询:
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 中使用自定义函数:
// 自定义统计函数
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:动态仪表板
创建自动更新的仪表板:
// 获取数据
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. 限制查询范围:
// ❌ 不推荐:查询所有笔记
FROM ""
// ✅ 推荐:限定文件夹
FROM "Projects"
// ✅ 推荐:限定标签
FROM #project2. 使用索引字段:
// ✅ 使用 frontmatter 字段
WHERE status = "active"
// ✅ 使用文件属性
WHERE file.cday >= date(today) - dur(7 days)3. 避免复杂计算:
// ❌ 不推荐:复杂嵌套
TABLE (
length(filter(...))
) as "计算"
// ✅ 推荐:简化查询
TABLE status, progress
WHERE status = "active"4. 分页查询:
// 使用 LIMIT 限制结果数量
TABLE title, date
FROM "Blog"
SORT date DESC
LIMIT 105. 缓存查询结果:
// 使用变量缓存查询结果
let allPages = dv.pages("");
// 多次使用同一查询
let projects = allPages.where(p => p.type === "project");
let tasks = allPages.where(p => p.type === "task");常见问题
Q1: 查询不显示结果?
检查清单:
1. 数据源是否存在
- 文件夹名称是否正确
- 标签是否存在
2. Frontmatter 格式是否正确
- YAML 语法是否正确
- 字段名是否拼写正确
3. 查询条件是否匹配
- 条件是否过于严格
- 是否有数据满足条件
4. 插件是否启用
- Dataview 是否已安装启用
- 是否有语法错误Q2: 如何调试查询?
// 调试方法:输出原始数据
let pages = dv.pages("Projects");
console.log(pages); // 在控制台查看
// 检查字段
dv.paragraph(`
字段列表:${pages.keys().join(", ")}
笔记数量:${pages.length}
第一条:${pages.first().file.link}
`);Q3: 查询速度慢怎么办?
优化方法:
1. 减少查询范围
- 使用 FROM 限定
- 添加 WHERE 条件
2. 简化查询
- 减少计算字段
- 避免嵌套查询
3. 使用索引
- 在 frontmatter 中定义字段
- 使用内置属性
4. 异步加载
- 分批查询
- 延迟加载参考资源
下一步
- Templater 高级教程 - 自动化模板
- QuickAdd 插件 - 快速添加内容
- 从0到1建立知识库 - 完整构建流程