Obsidian 核心插件数据库(Bases)之函数使用教程
数据库(Bases)是 Obsidian 官方推出的核心数据库插件,无需任何第三方工具就能把一批笔记聚合成可排序、可筛选的多种视图布局。
数据库内置了一套完整的函数系统,在筛选条件和公式两个场景中发挥作用——前者决定哪些笔记会被纳入视图,后者则在数据库中创建出经过计算或变换的衍生列。无论是对日期进行格式化、提取文件路径中的特定片段、统计列表元素数量,还是根据条件显示不同内容,背后都离不开函数的参与。值得一提的是,数据库的函数调用更接近面向对象风格:大多数函数以 值.函数名() 的链式形式出现,读起来更接近自然语言,全局函数则是例外,可以在任意位置直接使用。本文按函数类别逐一展开,配合实用示例帮助理解每个函数的实际用法。
目录
- Bases 与函数的关系
- 前提条件与版本要求
- 函数的两个使用场景:筛选与公式
- 全局函数
- 任意类型函数
- 日期函数
- 字符串函数
- 数字函数
- 列表函数
- 链接函数
- 文件函数
- 对象函数
- 正则表达式函数
- 常见问题与使用建议
1. Bases 与函数的关系
要理解函数在 Bases 中扮演的角色,先要明确 Bases 处理数据的基本逻辑。每一个 .base 文件本质上是一套视图配置:它从仓库中扫描符合条件的笔记,提取这些笔记的属性(Properties),以表格或卡片的形式呈现。整个过程分为两个阶段:
第一阶段是筛选(Filter),决定哪些笔记进入视图。筛选条件可以引用笔记的文件属性(如路径、标签、修改时间)以及 Frontmatter 中的自定义属性(如状态、优先级、截止日期)。函数在这里的作用是对这些属性值进行变换或比较,比如判断一个字符串是否以某个前缀开头、一个日期是否晚于今天,从而构成更精细的筛选逻辑。
第二阶段是公式(Formula),在视图中创建出一个全新的计算列。这个列的值并不来自笔记本身的属性,而是根据公式实时计算得出的结果——比如把创建日期格式化成更易读的形式、把多个标签拼接成一个显示字符串、或者根据某个属性的值判断当前状态并显示不同的标记。公式列可以像普通属性列一样用于视图展示、排序和进一步筛选。
函数贯穿这两个阶段,是让 Bases 从静态展示走向动态计算的关键。
💡 说明 除全局函数外,Bases 中的大多数函数依赖于值的类型。日期函数只能作用于日期类型的值,字符串函数只能作用于字符串类型的值,以此类推。调用类型不匹配的函数通常会在公式编辑器中触发语法错误提示。
2. 前提条件与版本要求
Obsidian 版本:Bases 核心插件从 Obsidian 1.9.0 起引入,首先向 Catalyst 早期访问用户开放,随后在正式版中逐步普及。建议使用 1.9.1 或更高版本,该版本修正了若干函数行为问题,并将函数命名规范从 snake_case(如 is_truthy)统一调整为 camelCase(如 isTruthy),两种风格之间存在不兼容,请确认使用的是正确的函数名格式。
⚠️ 注意 如果你在 1.9.1 之前的版本创建过
.base文件,升级到 1.9.1 后需要手动检查并更新文件中使用旧命名规范的函数名,否则这些函数将无法被正确识别。官方在 1.9.1 更新日志中对此做了专项说明。
启用核心插件:进入「设置 → 核心插件」,找到「数据库(Bases)」并将开关拨至开启状态。如果你尚未启用「属性视图(Properties)」,建议一并开启,因为 Bases 的属性列与属性面板密切配合。
创建第一个 Base 文件:在文件列表中右键点击任意文件夹,选择「新建数据库(New base)」,或通过命令面板执行「Bases: 创建新数据库」命令。生成的 .base 文件会在当前文件夹中创建。双击打开后,即可在界面顶部工具栏中访问「筛选(Filters)」和「属性(Properties)」两个入口,公式功能在「属性」面板中通过「添加公式(Add formula)」按钮进入。
💡 说明 从 1.9.5 版本起,Bases 引入了内置的公式编辑器,支持语法高亮、函数名自动补全以及实时错误提示。在此之前,公式需要手动在文本框中输入,容易出现拼写错误。如果你的版本低于 1.9.5,建议先在外部文本编辑器中确认公式语法无误后再粘贴进来。
3. 函数的两个使用场景:筛选与公式
在正式介绍各类函数之前,先了解它们具体写在什么地方、以什么样的形式工作,有助于在实际操作中快速定位。
在筛选中使用函数:点击视图工具栏的「筛选(Filters)」按钮,会弹出条件编辑界面。除了常见的「属性 → 运算符 → 值」结构,还可以通过「添加公式筛选」等入口输入自定义表达式。函数在此处的作用是在比较之前先对值做变换,例如:
file.mtime.format("YYYY-MM") == "2026-05"
这条筛选表达式的含义是:只显示最后修改时间落在 2026 年 5 月的笔记。file.mtime 是文件属性(日期类型),调用 .format() 函数后返回格式化字符串,再与目标字符串做等值比较。
在公式中使用函数:进入「属性 → 添加公式(Add formula)」,输入公式名称和公式表达式。公式表达式中可以引用笔记属性、文件属性,以及其他已定义的公式(通过 formula.公式名 的形式引用)。例如:
if(priority == "高", "⭐ 重要", "普通")
这条公式会读取每条笔记中名为 priority 的属性,根据其值决定显示「⭐ 重要」还是「普通」。公式列会实时计算,无需手动维护。
4. 全局函数
全局函数不依赖于任何特定类型即可使用,可以在筛选条件和公式的任意位置直接调用。
escapeHTML()
escapeHTML(html: string): string
将字符串中的 HTML 特殊字符转义,使其可以安全地嵌入 HTML 中。当你使用 html() 函数将某段文本渲染为 HTML 时,如果其中包含用户输入的内容或来自属性值的字符串,建议先通过 escapeHTML() 处理,防止标签意外解析。
例如:escapeHTML("<b>重要备注</b>") 返回 "<b>重要备注</b>",原本的 HTML 标签变为字面文本,不再被浏览器解析。
date()
date(date: string): date
将字符串解析为日期对象。date 字符串的格式应为 YYYY-MM-DD HH:mm:ss。当笔记的某个属性以字符串形式存储了日期信息,可以用此函数将其转换为日期类型,从而使用日期相关的函数和运算。
例如:date("2026-01-01 09:00:00") 将该字符串转换为一个可进行日期运算的日期对象。
duration()
duration(value: string): duration
将字符串解析为时间段。value 字符串的格式可参阅官方文档中的日期运算部分,常见写法如 "7d"(7 天)、"2h"(2 小时)、"30m"(30 分钟)。
需要注意两个细节:第一,在执行日期运算时,时间段字符串可以不经过显式解析直接使用,例如 now() + '7d' 是合法的。但如果要对时间段本身进行算术运算(例如将时间段乘以一个系数),则必须先用 duration() 显式转换,例如 now() + (duration('7d') * 3) 计算的是从现在起 21 天后的日期。第二,当时间段与标量(数字)进行乘除运算时,时间段必须写在左侧,例如 duration('3h') * 4 是正确的,而 4 * duration('3h') 则不被支持。
file()
file(path: string | file | url): file
返回给定文件路径或链接所对应的文件对象。接受字符串路径或链接对象作为输入,返回一个文件对象,可进一步使用文件类型的字段和函数。
例如:file(link("[[项目规划]]")) 或 file("Projects/当前项目.md")。
html()
html(html: string): html
将字符串转换为可在视图中渲染为 HTML 的代码片段。这个函数让公式列支持一定程度的富文本显示,例如插入带样式的标记、自定义颜色文本等。
⚠️ 注意 使用
html()函数渲染外部来源的内容时,务必先用escapeHTML()对原始字符串进行转义,避免注入风险。
if()
if(condition: any, trueResult: any, falseResult?: any): any
根据条件返回不同的值,是 Bases 中实现条件逻辑的核心工具。三个参数的含义如下:condition 是要判断的条件表达式;trueResult 是条件为真时返回的值;falseResult 是条件为假时返回的值,这个参数是可选的,如果省略则默认返回 null。
只要 condition 的结果为真值(truthy),函数就返回 trueResult;否则返回 falseResult。
💡 说明(按需调整) 以下为一个示例公式,用于根据笔记的
status属性值显示不同的标记:if(status == "完成", "✅ 已完成", "⏳ 进行中")
项目 示例特定值 通用写法 / 替换建议 属性名称 status替换为你自己笔记中实际使用的状态字段名 判断值 "完成"替换为你的字段中实际填写的值 显示文本 "✅ 已完成"/"⏳ 进行中"替换为你希望在视图中看到的文字或符号 公式的条件部分支持
==、!=、>、<、>=、<=等比较运算符,也支持&&(与)和||(或)的逻辑组合。
image()
image(path: string | file | url): image
返回一个图片对象,该对象会在视图中渲染为图片。接受本地文件路径、文件对象或外部 URL。
例如:image(cover) 读取笔记中名为 cover 的属性(通常存储图片路径或 URL),image("https://example.com/book-cover.jpg") 则直接渲染指定 URL 的图片。
💡 说明 要在 Bases 的表格列中显示图片,需要先在笔记属性中保存图片的路径或链接,再通过公式调用
image()函数将该属性值转换为可渲染的图片对象。仅将路径存储为普通文本属性,列中展示的依然是文字而非图片。
icon()
icon(name: string): icon
返回一个在视图中渲染为图标的值。图标名称须与 Obsidian 内置支持的 Lucide 图标库中的图标名称匹配,使用连字符风格的小写名称,如 "bookmark"、"star"、"check-circle" 等。
例如:icon("bookmark") 在视图列中显示书签图标。配合 if() 函数使用,可以根据条件在不同状态下显示不同图标,是一种增强视觉辨识度的常见做法。
link()
link(path: string | file, display?: value): Link
将字符串路径或文件对象解析为一个 Link 对象,在视图中渲染为可点击的链接。可选提供 display 参数来自定义链接的显示文本,而不是使用文件名。
例如:link("[[项目概览]]") 生成一个指向「项目概览」笔记的链接;link("[[项目概览]]", "查看项目") 生成的链接显示文本为「查看项目」而非文件名。
list()
list(element: any): List
如果传入的值本身已经是列表,则原样返回;如果传入的是一个非列表的单值,则将其包装成只有单个元素的列表。
这个函数在处理混合数据时非常有用。仓库中某些属性可能在不同笔记中表现不一致——有的笔记里该属性是单个字符串,有的笔记里是字符串列表。直接对这样的属性调用列表函数(如 .map()、.filter())可能因为类型不一致而出错。用 list() 先做一次包装,可以确保后续操作的一致性。
例如:list("研究方法论") 返回 ["研究方法论"],而 list(["研究", "归纳", "输出"]) 则原样返回 ["研究", "归纳", "输出"]。
max()
max(value1: number, value2: number…): number
接受两个或更多数字,返回其中的最大值。参数数量不固定,可以同时传入多个数字进行比较,例如 max(score1, score2, score3) 返回三个分数中最高的一个。
min()
min(value1: number, value2: number…): number
接受两个或更多数字,返回其中的最小值,用法与 max() 对称。
now()
now(): date
返回一个表示当前时刻的日期对象,包含完整的年、月、日、时、分、秒信息。常用于与其他日期属性进行比较,例如筛选出截止日期早于当前时刻的任务。
number()
number(input: any): number
尝试将传入的值转换为数字类型并返回。不同类型的转换规则如下:日期对象会被转换为从 Unix 纪元(1970-01-01 00:00:00 UTC)至该日期的毫秒数;布尔值 true 转换为 1,false 转换为 0;字符串会尝试解析为数字,若字符串内容不是合法数字则返回错误。
例如:number("9.8") 返回 9.8(数字类型)。
today()
today(): date
返回一个表示当前日期的日期对象,时间部分固定为零(即当天的 00:00:00)。与 now() 的区别在于,today() 忽略时间,适合用于按天比较的场景,例如筛选今天到期的事项而不需要精确到具体时刻。
random()
random(): number
返回一个 0 到 1 之间的随机小数。需要注意的是,随机数在每次加载视图时刷新,在不同视图之间切换也会触发刷新。
5. 任意类型函数
这一类函数可以作用于任意类型的值,包括字符串、数字、列表、对象等。
isTruthy()
any.isTruthy(): boolean
返回将该值强制转换为布尔值后的结果。在大多数情况下,非空字符串、非零数字、非空列表和非 null 对象都是真值(truthy),而空字符串、0、空列表、null 和 false 是假值(falsy)。
例如:42.isTruthy() 返回 true;0.isTruthy() 返回 false;"笔记".isTruthy() 返回 true;"".isTruthy() 返回 false。
isType()
any.isType(type: string): boolean
如果该值属于指定的类型,则返回 true。支持的类型名称包括 "string"、"number"、"boolean"、"date"、"list" 等。在对混合类型的列表进行处理前,可用此函数先筛选出特定类型的元素。
例如:"笔记标题".isType("string") 返回 true;true.isType("boolean") 返回 true;2026.isType("number") 返回 true。
toString()
any.toString(): string
返回任意值的字符串表示形式。数字、布尔值等非字符串类型在与字符串拼接或用于字符串函数之前,通常需要先用此函数进行转换。
例如:2026.toString() 返回 "2026"。
6. 日期函数
日期函数作用于日期和时间类型的值。日期值可以来自笔记属性中的日期字段,也可以由 now()、today()、date() 等全局函数生成。日期之间的大小比较可以直接使用 >、<、== 等运算符,更复杂的时间段运算可参考官方文档的日期运算部分。
字段
日期对象有以下可直接访问的字段:
| 字段 | 类型 | 描述 |
|---|---|---|
date.year | number | 日期的年份 |
date.month | number | 日期的月份(1–12) |
date.day | number | 日期的日 |
date.hour | number | 小时(0–23) |
date.minute | number | 分钟(0–59) |
date.second | number | 秒(0–59) |
date.millisecond | number | 毫秒(0–999) |
这些字段可以直接用于比较,例如 file.ctime.year == 2026 筛选出所有在 2026 年创建的笔记,file.mtime.month == 1 筛选出一月份修改过的笔记。
date()
date.date(): date
返回一个去除了时间部分的日期对象(即将时、分、秒、毫秒全部归零)。当你需要按天比较,而不希望时间部分影响结果时,可以用此方法先将带时间的日期对象「截断」到当天零点。
例如:now().date().format("YYYY-MM-DD HH:mm:ss") 的结果类似 "2026-05-03 00:00:00",时间部分已清零。
format()
date.format(format: string): string
按照指定的格式字符串将日期对象转换为字符串。格式规则遵循 Moment.js 标准,常用占位符包括 YYYY(四位年份)、MM(两位月份)、DD(两位日期)、HH(24 小时制小时)、mm(分钟)、ss(秒)。
例如:当笔记的创建时间为 2026 年 6 月 15 日时,file.ctime.format("YYYY年MM月DD日") 返回 "2026年06月15日";file.ctime.format("YYYY-MM-DD") 返回 "2026-06-15"。
time()
date.time(): string
返回日期对象的时间部分(时、分、秒)。结合 now() 使用时,可以读取当前时刻的时间字符串。
例如:now().time() 在下午两点半时返回类似 "14:30:00" 的字符串。
relative()
date.relative(): string
返回该日期与当前时刻的可读比较描述。这是一种便于快速理解时间距离的人性化表达方式,不需要手动计算时间差。
例如:file.mtime.relative() 可能返回 "2 weeks ago"(两周前)或 "in 3 days"(3 天后),具体文字取决于 Obsidian 的语言设置。
isEmpty()
date.isEmpty(): boolean
对于有效的日期对象,始终返回 false。此函数通常用于统一的空值检查逻辑,与其他类型的 isEmpty() 行为保持接口一致。
7. 字符串函数
字符串函数作用于字符序列类型的值。字符串类型的属性在 Obsidian 属性面板中对应「文本」类型字段。
字段
| 字段 | 类型 | 描述 |
|---|---|---|
string.length | number | 字符串中的字符数 |
string.length 返回字符串包含的字符总数(注意:中文字符每个计为 1),可直接用于比较,例如 title.length > 20 筛选出标题超过 20 个字符的笔记。
contains()
string.contains(value: string): boolean
如果字符串包含指定的子字符串,则返回 true。此函数不区分大小写(自 Obsidian 1.9.1 起)。
例如:"Obsidian 笔记".contains("笔记") 返回 true。
containsAll()
string.containsAll(…values: string): boolean
如果字符串同时包含所有指定的子字符串,则返回 true。适用于需要多关键词同时匹配的场景。
例如:"每日笔记与复盘".containsAll("每日", "复盘") 返回 true;"每日笔记与复盘".containsAll("每日", "项目") 返回 false,因为 ” 项目 ” 不在字符串中。
containsAny()
string.containsAny(…values: string): boolean
如果字符串包含任意一个指定的子字符串,则返回 true。适用于多关键词任一匹配即满足条件的场景。
例如:"知识管理系统".containsAny("知识", "信息", "数据") 返回 true,因为 ” 知识 ” 在字符串中。
endsWith()
string.endsWith(query: string): boolean
如果字符串以指定的子字符串结尾,则返回 true。
例如:"项目计划书".endsWith("计划书") 返回 true。
isEmpty()
string.isEmpty(): boolean
如果字符串没有任何字符,或字符串不存在(为 null),则返回 true。
例如:"归档".isEmpty() 返回 false;"".isEmpty() 返回 true。
这个函数在筛选时特别有用,例如 description.isEmpty() 可以找出所有没有填写描述属性的笔记。
lower()
string.lower(): string
将字符串中所有大写字母转换为小写,返回转换后的新字符串,不修改原值。
例如:"Obsidian".lower() 返回 "obsidian"。在需要做大小写不敏感比较时,可以先对双方都调用 lower() 再比较。
replace()
string.replace(pattern: string | Regexp, replacement: string): string
在字符串中查找 pattern 并用 replacement 替换,两者的行为取决于 pattern 的类型:
- 若
pattern是字符串,则所有匹配的子字符串都会被替换。 - 若
pattern是正则表达式,则是否替换全部取决于是否带有g(全局)标志:不带g只替换第一个匹配项,带g则替换所有匹配项。
例如:"2026:05:03".replace(/:/, "-") 返回 "2026-05:03"(只替换第一个冒号);"2026:05:03".replace(/:/g, "-") 返回 "2026-05-03"(替换所有冒号)。
💡 说明 当使用字符串作为
pattern时,替换的是所有匹配,行为等同于正则表达式加g标志。如果只想替换第一处,请改用正则表达式(不带g标志)。
repeat()
string.repeat(count: number): string
将字符串重复指定次数后返回拼接结果。
例如:"★".repeat(5) 返回 "★★★★★"。这个函数可以配合 if() 和数字属性,生成星级评分之类的可视化标记。
reverse()
string.reverse(): string
将字符串中的字符逆序排列后返回。
例如:"notes".reverse() 返回 "seton"。
slice()
string.slice(start: number, end?: number): string
返回字符串从 start 位置(包含)到 end 位置(不包含)的子字符串。索引从 0 开始计数。若省略 end,则截取到字符串末尾。
例如:"Obsidian".slice(0, 3) 返回 "Obs"(取前三个字符);"Obsidian".slice(3) 返回 "idian"(从索引 3 截取到末尾)。
split()
string.split(separator: string | Regexp, n?: number): list
以指定分隔符将字符串拆分为子字符串列表。可选参数 n 限制返回的元素数量,结果只包含前 n 个元素。
例如:"读书/摘录/归档".split("/", 2) 和 "读书/摘录/归档".split(/\//, 2) 都返回 ["读书", "摘录"](取分割结果的前 2 项)。不传入 n 时则返回全部分割结果。
startsWith()
string.startsWith(query: string): boolean
如果字符串以指定的子字符串开头,则返回 true。
例如:"daily-2026-05-03".startsWith("daily") 返回 true。在筛选日记类笔记时,可以用此函数配合文件名属性来匹配特定命名格式的文件。
title()
string.title(): string
将字符串转换为标题大小写(Title Case)格式,即每个单词的首字母大写、其余字母小写。
例如:"personal knowledge management".title() 返回 "Personal Knowledge Management"。
💡 说明
title()对中文字符不产生效果,因为汉字没有大小写之分。此函数主要适用于包含英文单词的属性值。
trim()
string.trim(): string
去除字符串两端(开头和结尾)的空白字符(包括空格、制表符等),返回处理后的新字符串,不影响字符串内部的空格。
例如:" Obsidian ".trim() 返回 "Obsidian"。在属性值可能因手误带入多余空格时,用 trim() 做一次清理可以提升比较的准确性。
8. 数字函数
数字函数作用于数值类型的属性,例如笔记中定义为「数字」类型的字段,或通过公式计算得出的数值结果。
abs()
number.abs(): number
返回数字的绝对值(去掉负号的版本)。
例如:(-42).abs() 返回 42。在处理可能出现正负差值的场景(如进度偏差、温差等)时,abs() 可以统一转为正值再比较大小。
ceil()
number.ceil(): number
将数字向上取整为最接近的整数(天花板取整)。无论小数部分多小,只要不是整数就会进位。
例如:(3.2).ceil() 返回 4。
floor()
number.floor(): number
将数字向下取整为最接近的整数(地板取整),直接舍弃小数部分。
例如:(7.8).floor() 返回 7。
isEmpty()
number.isEmpty(): boolean
如果数字不存在(属性未填写,值为 null),则返回 true;如果属性已有值(包括值为 0 的情况),则返回 false。
例如:100.isEmpty() 返回 false;当某个数字类型属性未在笔记中填写时,对其调用 isEmpty() 返回 true,可以用来筛选出缺少该属性值的笔记。
round()
number.round(digits: number): number
将数字四舍五入。不传入参数时,四舍五入到最接近的整数;传入 digits 参数时,四舍五入到指定的小数位数。
例如:(4.567).round() 返回 5;(4.567).round(2) 返回 4.57。
toFixed()
number.toFixed(precision: number): string
以定点表示法将数字格式化为字符串,保留 precision 位小数。注意返回值是字符串类型,而非数字。
例如:(2.71828).toFixed(3) 返回 "2.718"。在需要统一显示小数位数(如金额、比率)时,toFixed() 比 round() 更适合用于展示,因为它会保留末尾的零(例如 (3.10).toFixed(2) 返回 "3.10" 而非 "3.1")。
9. 列表函数
列表函数作用于有序元素的集合,对应 Obsidian 属性中「列表」类型的字段(即多值文本字段),也适用于由其他函数返回的列表结果。
字段
| 字段 | 类型 | 描述 |
|---|---|---|
list.length | number | 列表中的元素数量 |
list.length 直接返回列表包含的元素个数,常用于筛选(如 tags.length >= 3 找出标签数不少于 3 个的笔记)和公式(如将元素数量作为指标展示)。
contains()
list.contains(value: any): boolean
如果列表中包含指定的值,则返回 true。
例如:["写作", "阅读", "思考"].contains("阅读") 返回 true。在筛选中对标签列表使用此函数,可以找出含有特定标签的笔记,不过更推荐使用文件函数中的 file.hasTag() 来处理标签筛选。
containsAll()
list.containsAll(…values: any): boolean
如果列表同时包含所有指定的值,则返回 true。
例如:["写作", "阅读", "归档"].containsAll("写作", "归档") 返回 true;["写作", "阅读", "归档"].containsAll("写作", "发布") 返回 false。
containsAny()
list.containsAny(…values: any): boolean
如果列表包含任意一个指定的值,则返回 true。
例如:["每日", "项目", "参考"].containsAny("参考", "存档") 返回 true,因为 ” 参考 ” 在列表中。
filter()
list.filter(value: Boolean): list
遍历列表中的每个元素,对每个元素求值表达式,保留结果为真的元素,返回由这些元素组成的新列表。表达式中可以使用内置变量 value(当前元素的值)和 index(当前元素在原列表中的索引,从 0 开始)。
例如:[10, 20, 30, 40].filter(value >= 25) 返回 [30, 40],只保留大于等于 25 的元素。
flat()
list.flat(): list
将嵌套列表展平为一个单层列表。只展平一层,即列表的直接子列表会被合并,但更深层的嵌套不会继续展开。
例如:["第一章", ["第二章", "第三章"]].flat() 返回 ["第一章", "第二章", "第三章"]。
isEmpty()
list.isEmpty(): boolean
如果列表没有任何元素,则返回 true。
例如:["笔记"].isEmpty() 返回 false;[].isEmpty() 返回 true。
join()
list.join(separator: string): string
将列表中的所有元素用指定的分隔符连接为一个字符串。
例如:["写作", "阅读", "思考"].join(" → ") 返回 "写作 → 阅读 → 思考"。在公式列中使用 join() 可以将列表类型的属性(如多标签)合并为单行文本展示。
map()
list.map(value: Any): list
遍历列表中的每个元素,对每个元素求值表达式,将结果收集为新列表返回。表达式中同样可以使用 value(当前元素)和 index(当前索引)。
例如:[10, 20, 30].map(value * 2) 返回 [20, 40, 60],对每个元素做了乘以 2 的变换。map() 经常与 join() 配合,先变换每个元素,再拼接为字符串显示。
reduce()
list.reduce(expression: Any, acc: Any): Any
将列表归约(折叠)为单个值,通过对每个元素执行表达式、并将结果传递给下一次迭代的累加器来完成。可用变量包括 value(当前元素)、index(当前索引)和 acc(当前累积值)。第二个参数 acc 是累加器的初始值。
例如,对一组评分求和:[8, 9, 7, 10].reduce(acc + value, 0) 返回 34。
若要找出一个数字列表中的最大值(兼容混合类型的属性,先过滤非数字再归约):
ratings.filter(value.isType("number")).reduce(if(acc == null || value > acc, value, acc), null)
⚠️ 注意(特定设置) 以上公式中的
ratings是一个示例属性名,并非通用字段。请替换为你自己笔记中实际存储数值的列表属性名。
项目 示例特定值 通用写法 / 替换建议 属性名 ratings替换为你实际使用的数字列表属性名
reverse()
list.reverse(): list
将列表元素的顺序完全颠倒后返回新列表。
例如:["一月", "二月", "三月"].reverse() 返回 ["三月", "二月", "一月"]。
slice()
list.slice(start: number, end?: number): list
返回列表从 start 位置(包含)到 end 位置(不包含)的浅拷贝片段。索引从 0 开始。省略 end 时截取到列表末尾。
例如:[10, 20, 30, 40, 50].slice(1, 4) 返回 [20, 30, 40](索引 1、2、3 对应的元素)。
sort()
list.sort(): list
将列表元素从小到大排序。数字按数值大小,字符串按字母/Unicode 码点顺序排序。
例如:[5, 1, 3, 2, 4].sort() 返回 [1, 2, 3, 4, 5];["梅", "兰", "竹", "菊"].sort() 按 Unicode 顺序排列。
unique()
list.unique(): list
去除列表中的重复元素,返回由唯一元素组成的新列表,保留首次出现的元素,后续重复项被丢弃。
例如:["标签A", "标签B", "标签A", "标签C"].unique() 返回 ["标签A", "标签B", "标签C"]。在属性值可能因数据来源不同而出现重复时,unique() 可以做去重处理。
10. 链接函数
链接函数作用于 Link 类型的值。链接对象可以由文件属性(file.asLink())、全局函数 link() 或笔记属性中的 WikiLink 格式字段生成。
asFile()
link.asFile(): file
如果链接指向一个在仓库中实际存在的本地文件,则返回对应的文件对象,可进一步使用文件类型的字段和函数。如果链接指向的文件不存在,返回 null。
例如:link("[[读书笔记-活着]]").asFile() 返回「读书笔记 - 活着」这个文件对应的文件对象,之后可以继续调用 file.mtime、file.hasTag() 等文件函数。
linksTo()
link.linksTo(file): boolean
检查该链接所代表的文件是否包含指向 file 的内部链接,若是则返回 true。这个函数可以用来构建基于链接关系的筛选逻辑。
11. 文件函数
文件函数作用于仓库中的文件对象。在 Bases 的筛选和公式中,每条记录本身就代表一个文件,可以通过 file. 前缀直接访问以下字段和函数,无需额外转换。
字段
以下字段可直接用于文件对象:
| 字段 | 类型 | 描述 |
|---|---|---|
file.name | string | 此文件的完整名称(含扩展名) |
file.basename | string | 不含扩展名的文件名称 |
file.path | string | 相对于仓库根目录的完整文件路径 |
file.folder | string | 父文件夹的完整路径 |
file.ext | string | 此文件的扩展名 |
file.size | number | 此文件的大小,以字节为单位 |
file.properties | object | 此文件的笔记属性集合 |
file.tags | list | 此文件的所有标签,包括行内标签 |
file.links | list | 此文件中的所有内部链接 |
file.ctime | date | 此文件的创建时间戳 |
file.mtime | date | 此文件最后一次修改的时间戳 |
这些字段覆盖了日常使用中最高频的文件元数据。file.ctime 和 file.mtime 属于日期类型,可以直接使用日期函数进行格式化或比较;file.size 属于数字类型,可用数字函数处理;file.tags 和 file.links 属于列表类型,可用列表函数操作。
asLink()
file.asLink(display?: string): Link
将文件对象转换为一个 Link 对象,在视图中渲染为可点击的内部链接。可选提供 display 参数自定义链接的显示文字。
例如:file.asLink() 生成一个以文件名为显示文本的链接;file.asLink("查看详情") 生成一个显示文本为「查看详情」的链接。
hasLink()
file.hasLink(otherFile: file | string): boolean
如果该文件包含指向 otherFile 的内部链接,则返回 true。otherFile 可以是另一个文件对象,也可以是字符串形式的文件路径。
例如:当「项目总览」这个笔记中有指向「阶段一计划」的链接时,file.hasLink("阶段一计划") 返回 true。
hasProperty()
file.hasProperty(name: string): boolean
如果笔记的 Frontmatter 中存在指定名称的属性(无论其值是否为空),则返回 true。用于筛选出已定义某个属性的笔记,与检查属性值是否为空不同。
hasTag()
file.hasTag(…values: string): boolean
如果文件具有 values 中任意一个标签,则返回 true。支持同时传入多个标签名,任一匹配即满足条件。匹配范围包含嵌套标签:如果文件有标签 #读书/精读,则 file.hasTag("读书") 也会返回 true。
例如:file.hasTag("读书", "书评") 在文件具有 #读书 或 #书评(及其子标签)时返回 true。
💡 说明 传入
hasTag()的标签名称不需要加#前缀,直接写标签的文字部分即可,如"读书"而非"#读书"。
inFolder()
file.inFolder(folder: string): boolean
如果文件位于指定文件夹或其任意子文件夹中,则返回 true。
例如:file.inFolder("Projects") 会匹配 Projects/ 目录下的所有文件,包括 Projects/当前/任务.md 这样的多层子目录中的文件。
💡 说明(按需调整) 以下以筛选特定文件夹中笔记的场景为例:
项目 示例特定值 通用写法 / 替换建议 文件夹名 "Projects"替换为你仓库中实际想要筛选的文件夹路径
inFolder()的文件夹参数支持相对路径,如"Archive/2025"会只匹配该路径下的文件,而"Archive"则会匹配 Archive 及其所有子目录。
12. 对象函数
对象函数作用于键值对集合类型的值。在 Bases 中,file.properties 字段就是一个对象,包含了某个笔记的所有 Frontmatter 属性。
isEmpty()
object.isEmpty(): boolean
如果对象没有任何自身属性(键),则返回 true。
例如:{}.isEmpty() 返回 true;{"状态": "完成"}.isEmpty() 返回 false。
keys()
object.keys(): list
返回包含该对象所有键(属性名称)的列表。结合 file.properties 使用,可以列出某个笔记定义了哪些 Frontmatter 字段。
values()
object.values(): list
返回包含该对象所有值的列表,顺序与 keys() 对应。可以进一步对这个列表使用列表函数进行处理。
13. 正则表达式函数
正则表达式函数作用于正则表达式模式对象。在 Bases 的公式中,正则表达式用斜杠包裹,如 /pattern/,支持常见的正则修饰符(如 i 表示不区分大小写,g 表示全局匹配)。
matches()
regexp.matches(value: string): boolean
如果正则表达式与 value 字符串匹配,则返回 true。这是在 Bases 中进行模式匹配的主要方式,适合处理用简单字符串比较无法覆盖的复杂格式验证场景。
例如:/^\d{4}-\d{2}-\d{2}/.matches("2026-05-03") 返回 true,用于验证字符串是否符合 YYYY-MM-DD 的日期格式;/[A-Z]/.matches("obsidian") 返回 false,因为字符串中没有大写字母。
在筛选中结合属性使用的写法如下:
/^P-\d+/.matches(project_id)
这条筛选表达式会找出 project_id 属性值符合「以字母 P 和连字符开头、后跟一个或多个数字」格式的所有笔记。
💡 说明(按需调整) 以上正则表达式
/^P-\d+/和属性名project_id均为示例特定值:
项目 示例特定值 通用写法 / 替换建议 正则模式 /^P-\d+/替换为你需要匹配的实际模式 属性名 project_id替换为你笔记中实际存储待匹配文本的属性名
14. 常见问题与使用建议
14.1 函数名大小写错误导致公式失效
Obsidian 1.9.1 将 Bases 函数的命名规范从 snake_case 统一改为 camelCase,例如旧版的 is_truthy 变更为 isTruthy,to_string 变更为 toString。如果你在低版本创建的 .base 文件在升级后出现公式失效或报错,首先检查所用函数名是否已按新规范更新。官方更新日志(1.9.1 版本)有完整的改名对照,可作参考。
14.2 类型不匹配导致函数无效
Bases 的函数是强类型的——日期函数只能作用于日期类型,字符串函数只能作用于字符串类型。如果属性中的值与预期类型不一致(例如某个「日期」属性中存了普通文本字符串),直接调用日期函数会报错。此时可以先用全局的 date() 函数将字符串显式转换为日期对象,再调用日期函数,例如 date(my_date_string).format("YYYY-MM-DD")。
对于可能存在混合类型值的列表属性,建议在对列表进行操作前,先用 .filter(value.isType("目标类型")) 过滤掉类型不符合的元素,再执行后续运算。
14.3 contains() 的大小写行为
自 1.9.1 起,字符串的 contains() 函数改为大小写不敏感。这意味着 "Obsidian".contains("obsidian") 也会返回 true。如果你的场景需要区分大小写,可以先对双方都调用 .lower() 转为小写再比较,通过这种方式手动实现大小写敏感的匹配。
14.4 公式可以引用其他公式
Bases 的公式支持相互引用:如果你已经定义了一个名为 days_overdue 的公式,可以在另一个公式中通过 formula.days_overdue 来引用它的计算结果,进一步构建层次化的衍生计算。这个特性非常适合将复杂逻辑拆分为多个简单公式,逐步组合,保持每个公式的可读性。
14.5 list() 函数用于统一混合类型属性
仓库规模增大后,同一个属性名在不同笔记中可能出现「单值字符串」和「字符串列表」并存的情况(例如部分笔记的 source 属性只填了一个来源,另一些笔记填了多个)。对这样的属性直接调用 .map() 或 .filter() 等列表函数,在值为单值时会报错。用 list(source) 包裹一下,可以确保无论单值还是列表,后续的列表函数都能正常运行。
14.6 筛选中使用 this 引用当前选中的笔记
Bases 的筛选表达式中,this 是一个特殊变量,指向当前在编辑器中聚焦的笔记(而非数据库正在遍历的笔记)。这一特性可以用来实现动态关联视图。例如,将筛选设为 file.hasLink(this.file.basename) 后,数据库会显示所有链接到当前聚焦笔记的文件,配合侧边栏嵌入使用,效果类似于实时的反向链接视图。
✅ 推荐做法 初次接触 Bases 函数时,建议从公式列入手,而非直接用在筛选表达式上。公式列可以实时预览每一行笔记的计算结果,便于观察函数的输出是否符合预期,逐步调整到满意后,再考虑将类似逻辑移植到筛选条件中使用。
14.7 与 Dataview 的关系
Bases 是官方内置的查询与视图方案,而 Dataview 是历史更久、功能更广的社区插件。两者并不互斥,可以在同一个仓库中共存。目前 Bases 主要支持表格和卡片视图,对于需要列表视图、日历视图、自定义 JavaScript 逻辑的场景,Dataview 仍有其不可替代的价值。可以将 Bases 视为轻量级、原生集成的替代方案,在适合的场景下优先使用,其余情况继续沿用 Dataview。
14.8 嵌入 Base 到其他笔记
与图片和其他文件一样,.base 文件可以通过 ![[文件名.base]] 的内嵌语法嵌入到任意笔记中,在笔记正文中直接呈现数据库视图。嵌入状态下,this 指向包含该嵌入语法的外层笔记,可以借此实现与当前笔记内容关联的动态视图——这是在日记模板或项目笔记中内嵌关联任务列表的常见做法。