名称: obsidian-bases
描述: 创建和编辑Obsidian基础文件(.base文件),包含视图、过滤器、公式和摘要。当处理.base文件、创建类似数据库的笔记视图,或当用户提到Obsidian中的基础、表视图、卡片视图、过滤器或公式时使用。
Obsidian 基础技能
此技能使技能兼容代理能够创建和编辑有效的Obsidian基础文件(.base文件),包括视图、过滤器和所有相关配置。
概述
Obsidian基础是基于YAML的文件,用于定义Obsidian仓库中笔记的动态视图。基础文件可以包含多个视图、全局过滤器、公式、属性配置和自定义摘要。
文件格式
基础文件使用.base扩展名,并包含有效的YAML。它们也可以嵌入到Markdown代码块中。
完整架构
# 全局过滤器适用于基础中的所有视图
filters:
# 可以是单个过滤器字符串
# 或递归过滤器对象,使用and/or/not
and: []
or: []
not: []
# 定义在所有视图中可使用的公式属性
formulas:
公式名称: '表达式'
# 配置属性的显示名称和设置
properties:
属性名称:
displayName: "显示名称"
formula.公式名称:
displayName: "公式显示名称"
file.ext:
displayName: "扩展名"
# 定义自定义摘要公式
summaries:
自定义摘要名称: 'values.mean().round(3)'
# 定义一个或多个视图
views:
- type: table | cards | list | map
name: "视图名称"
limit: 10 # 可选:限制结果数量
groupBy: # 可选:分组结果
property: 属性名称
direction: ASC | DESC
filters: # 视图特定过滤器
and: []
order: # 按顺序显示的属性
- file.name
- 属性名称
- formula.公式名称
summaries: # 将属性映射到摘要公式
属性名称: Average
过滤器语法
过滤器用于缩小结果范围。可以全局应用或按视图应用。
过滤器结构
# 单个过滤器
filters: '状态 == "完成"'
# AND - 所有条件必须为真
filters:
and:
- '状态 == "完成"'
- '优先级 > 3'
# OR - 任何条件可以为真
filters:
or:
- 'file.hasTag("书籍")'
- 'file.hasTag("文章")'
# NOT - 排除匹配项
filters:
not:
- 'file.hasTag("归档")'
# 嵌套过滤器
filters:
or:
- file.hasTag("标签")
- and:
- file.hasTag("书籍")
- file.hasLink("教科书")
- not:
- file.hasTag("书籍")
- file.inFolder("必读")
过滤器运算符
| 运算符 |
描述 |
== |
等于 |
!= |
不等于 |
> |
大于 |
< |
小于 |
>= |
大于或等于 |
<= |
小于或等于 |
&& |
逻辑与 |
|| |
逻辑或 |
| <code>!</code> |
逻辑非 |
属性
三种属性类型
- 笔记属性 - 来自frontmatter:
note.author 或仅 author
- 文件属性 - 文件元数据:
file.name、file.mtime 等
- 公式属性 - 计算值:
formula.my_formula
文件属性参考
| 属性 |
类型 |
描述 |
file.name |
字符串 |
文件名 |
file.basename |
字符串 |
不带扩展名的文件名 |
file.path |
字符串 |
文件完整路径 |
file.folder |
字符串 |
父文件夹路径 |
file.ext |
字符串 |
文件扩展名 |
file.size |
数字 |
文件大小(字节) |
file.ctime |
日期 |
创建时间 |
file.mtime |
日期 |
修改时间 |
file.tags |
列表 |
文件中的所有标签 |
file.links |
列表 |
文件中的内部链接 |
file.backlinks |
列表 |
链接到此文件的文件 |
file.embeds |
列表 |
笔记中的嵌入 |
file.properties |
对象 |
所有frontmatter属性 |
this 关键字
- 在主内容区域:引用基础文件本身
- 当嵌入时:引用嵌入文件
- 在侧边栏:引用主内容中的活动文件
公式语法
公式从属性计算值。在formulas部分定义。
formulas:
# 简单算术
total: "价格 * 数量"
# 条件逻辑
status_icon: 'if(完成, "✅", "⏳")'
# 字符串格式化
formatted_price: 'if(价格, price.toFixed(2) + " 美元")'
# 日期格式化
created: 'file.ctime.format("YYYY-MM-DD")'
# 复杂表达式
days_old: '((now() - file.ctime) / 86400000).round(0)'
函数参考
全局函数
| 函数 |
签名 |
描述 |
date() |
date(string): date |
将字符串解析为日期。格式:YYYY-MM-DD HH:mm:ss |
duration() |
duration(string): duration |
解析持续时间字符串 |
now() |
now(): date |
当前日期和时间 |
today() |
today(): date |
当前日期(时间 = 00:00:00) |
if() |
if(condition, trueResult, falseResult?) |
条件语句 |
min() |
min(n1, n2, ...): number |
最小数字 |
max() |
max(n1, n2, ...): number |
最大数字 |
number() |
number(any): number |
转换为数字 |
link() |
link(path, display?): Link |
创建链接 |
list() |
list(element): List |
如果不是列表则包装为列表 |
file() |
file(path): file |
获取文件对象 |
image() |
image(path): image |
创建用于渲染的图像 |
icon() |
icon(name): icon |
按名称的Lucide图标 |
html() |
html(string): html |
渲染为HTML |
escapeHTML() |
escapeHTML(string): string |
转义HTML字符 |
任意类型函数
| 函数 |
签名 |
描述 |
isTruthy() |
any.isTruthy(): boolean |
强制转换为布尔值 |
isType() |
any.isType(type): boolean |
检查类型 |
toString() |
any.toString(): string |
转换为字符串 |
日期函数和字段
字段: date.year、date.month、date.day、date.hour、date.minute、date.second、date.millisecond
| 函数 |
签名 |
描述 |
date() |
date.date(): date |
移除时间部分 |
format() |
date.format(string): string |
使用Moment.js模式格式化 |
time() |
date.time(): string |
获取时间为字符串 |
relative() |
date.relative(): string |
人类可读的相对时间 |
isEmpty() |
date.isEmpty(): boolean |
日期总是为假 |
日期算术
# 持续时间单位:y/年/年, M/月/月, d/天/天,
# w/周/周, h/小时/小时, m/分钟/分钟, s/秒/秒
# 加减持续时间
"date + \"1M\"" # 添加1个月
"date - \"2h\"" # 减去2小时
"now() + \"1 天\"" # 明天
"today() + \"7d\"" # 从今天起一周后
# 减去日期以获取毫秒差
"now() - file.ctime"
# 复杂持续时间算术
"now() + (duration('1d') * 2)"
字符串函数
字段: string.length
| 函数 |
签名 |
描述 |
contains() |
string.contains(value): boolean |
检查子字符串 |
containsAll() |
string.containsAll(...values): boolean |
所有子字符串存在 |
containsAny() |
string.containsAny(...values): boolean |
任何子字符串存在 |
startsWith() |
string.startsWith(query): boolean |
以查询开头 |
endsWith() |
string.endsWith(query): boolean |
以查询结尾 |
isEmpty() |
string.isEmpty(): boolean |
为空或不存在 |
lower() |
string.lower(): string |
转换为小写 |
title() |
string.title(): string |
转换为标题大小写 |
trim() |
string.trim(): string |
移除空格 |
replace() |
string.replace(pattern, replacement): string |
替换模式 |
repeat() |
string.repeat(count): string |
重复字符串 |
reverse() |
string.reverse(): string |
反转字符串 |
slice() |
string.slice(start, end?): string |
子字符串 |
split() |
string.split(separator, n?): list |
分割为列表 |
数字函数
| 函数 |
签名 |
描述 |
abs() |
number.abs(): number |
绝对值 |
ceil() |
number.ceil(): number |
向上取整 |
floor() |
number.floor(): number |
向下取整 |
round() |
number.round(digits?): number |
四舍五入到指定位数 |
toFixed() |
number.toFixed(precision): string |
定点表示法 |
isEmpty() |
number.isEmpty(): boolean |
不存在 |
列表函数
字段: list.length
| 函数 |
签名 |
描述 |
contains() |
list.contains(value): boolean |
元素存在 |
containsAll() |
list.containsAll(...values): boolean |
所有元素存在 |
containsAny() |
list.containsAny(...values): boolean |
任何元素存在 |
filter() |
list.filter(expression): list |
按条件过滤(使用value、index) |
map() |
list.map(expression): list |
转换元素(使用value、index) |
reduce() |
list.reduce(expression, initial): any |
减少为单个值(使用value、index、acc) |
flat() |
list.flat(): list |
展平嵌套列表 |
join() |
list.join(separator): string |
连接为字符串 |
reverse() |
list.reverse(): list |
反转顺序 |
slice() |
list.slice(start, end?): list |
子列表 |
sort() |
list.sort(): list |
升序排序 |
unique() |
list.unique(): list |
移除重复项 |
isEmpty() |
list.isEmpty(): boolean |
无元素 |
文件函数
| 函数 |
签名 |
描述 |
asLink() |
file.asLink(display?): Link |
转换为链接 |
hasLink() |
file.hasLink(otherFile): boolean |
链接到文件 |
hasTag() |
file.hasTag(...tags): boolean |
具有任何标签 |
hasProperty() |
file.hasProperty(name): boolean |
具有属性 |
inFolder() |
file.inFolder(folder): boolean |
在文件夹或子文件夹中 |
链接函数
| 函数 |
签名 |
描述 |
asFile() |
link.asFile(): file |
获取文件对象 |
linksTo() |
link.linksTo(file): boolean |
链接到文件 |
对象函数
| 函数 |
签名 |
描述 |
isEmpty() |
object.isEmpty(): boolean |
无属性 |
keys() |
object.keys(): list |
键列表 |
values() |
object.values(): list |
值列表 |
正则表达式函数
| 函数 |
签名 |
描述 |
matches() |
regexp.matches(string): boolean |
测试是否匹配 |
视图类型
表视图
views:
- type: table
name: "我的表"
order:
- file.name
- 状态
- 到期日期
summaries:
价格: Sum
数量: Average
卡片视图
views:
- type: cards
name: "图库"
order:
- file.name
- 封面图像
- 描述
列表视图
views:
- type: list
name: "简单列表"
order:
- file.name
- 状态
地图视图
需要纬度/经度属性和地图社区插件。
views:
- type: map
name: "位置"
# 特定于地图的纬度/经度属性设置
默认摘要公式
| 名称 |
输入类型 |
描述 |
Average |
数字 |
数学均值 |
Min |
数字 |
最小数字 |
Max |
数字 |
最大数字 |
Sum |
数字 |
所有数字之和 |
Range |
数字 |
最大 - 最小 |
Median |
数字 |
数学中位数 |
Stddev |
数字 |
标准差 |
Earliest |
日期 |
最早日期 |
Latest |
日期 |
最新日期 |
Range |
日期 |
最新 - 最早 |
Checked |
布尔值 |
真值计数 |
Unchecked |
布尔值 |
假值计数 |
Empty |
任意 |
空值计数 |
Filled |
任意 |
非空值计数 |
Unique |
任意 |
唯一值计数 |
完整示例
任务跟踪基础
filters:
and:
- file.hasTag("任务")
- 'file.ext == "md"'
formulas:
days_until_due: 'if(到期, ((date(到期) - today()) / 86400000).round(0), "")'
is_overdue: 'if(到期, date(到期) < today() && 状态 != "完成", false)'
priority_label: 'if(优先级 == 1, "🔴 高", if(优先级 == 2, "🟡 中", "🟢 低"))'
properties:
状态:
displayName: 状态
formula.days_until_due:
displayName: "到期天数"
formula.priority_label:
displayName: 优先级
views:
- type: table
name: "活动任务"
filters:
and:
- '状态 != "完成"'
order:
- file.name
- 状态
- formula.priority_label
- 到期
- formula.days_until_due
groupBy:
property: 状态
direction: ASC
summaries:
formula.days_until_due: Average
- type: table
name: "已完成"
filters:
and:
- '状态 == "完成"'
order:
- file.name
- 完成日期
阅读列表基础
filters:
or:
- file.hasTag("书籍")
- file.hasTag("文章")
formulas:
reading_time: 'if(页数, (页数 * 2).toString() + " 分钟", "")'
status_icon: 'if(状态 == "阅读中", "📖", if(状态 == "完成", "✅", "📚"))'
year_read: 'if(完成日期, date(完成日期).year, "")'
properties:
作者:
displayName: 作者
formula.status_icon:
displayName: ""
formula.reading_time:
displayName: "预估时间"
views:
- type: cards
name: "图书馆"
order:
- 封面
- file.name
- 作者
- formula.status_icon
filters:
not:
- '状态 == "已放弃"'
- type: table
name: "阅读列表"
filters:
and:
- '状态 == "待读"'
order:
- file.name
- 作者
- 页数
- formula.reading_time
项目笔记基础
filters:
and:
- file.inFolder("项目")
- 'file.ext == "md"'
formulas:
last_updated: 'file.mtime.relative()'
link_count: 'file.links.length'
summaries:
avgLinks: 'values.filter(value.isType("number")).mean().round(1)'
properties:
formula.last_updated:
displayName: "更新"
formula.link_count:
displayName: "链接"
views:
- type: table
name: "所有项目"
order:
- file.name
- 状态
- formula.last_updated
- formula.link_count
summaries:
formula.link_count: avgLinks
groupBy:
property: 状态
direction: ASC
- type: list
name: "快速列表"
order:
- file.name
- 状态
每日笔记索引
filters:
and:
- file.inFolder("每日笔记")
- '/^\d{4}-\d{2}-\d{2}$/.matches(file.basename)'
formulas:
word_estimate: '(file.size / 5).round(0)'
day_of_week: 'date(file.basename).format("dddd")'
properties:
formula.day_of_week:
displayName: "星期"
formula.word_estimate:
displayName: "~字数"
views:
- type: table
name: "近期笔记"
limit: 30
order:
- file.name
- formula.day_of_week
- formula.word_estimate
- file.mtime
嵌入基础
嵌入Markdown文件:
![[我的基础.base]]
<!-- 特定视图 -->
![[我的基础.base#视图名称]]
YAML引用规则
- 使用单引号处理包含双引号的公式:
'if(完成, "是", "否")'
- 使用双引号处理简单字符串:
"我的视图名称"
- 在复杂表达式中正确转义嵌套引号
常见模式
按标签过滤
filters:
and:
- file.hasTag("项目")
按文件夹过滤
filters:
and:
- file.inFolder("笔记")
按日期范围过滤
filters:
and:
- 'file.mtime > now() - "7d"'
按属性值过滤
filters:
and:
- '状态 == "活动"'
- '优先级 >= 3'
结合多个条件
filters:
or:
- and:
- file.hasTag("重要")
- '状态 != "完成"'
- and:
- '优先级 == 1'
- '到期 != ""'
参考