Obsidian 核心插件数据库(Bases)之函数使用教程

数据库(Bases)是 Obsidian 官方推出的核心数据库插件,无需任何第三方工具就能把一批笔记聚合成可排序、可筛选的多种视图布局。

数据库内置了一套完整的函数系统,在筛选条件和公式两个场景中发挥作用——前者决定哪些笔记会被纳入视图,后者则在数据库中创建出经过计算或变换的衍生列。无论是对日期进行格式化、提取文件路径中的特定片段、统计列表元素数量,还是根据条件显示不同内容,背后都离不开函数的参与。值得一提的是,数据库的函数调用更接近面向对象风格:大多数函数以 值.函数名() 的链式形式出现,读起来更接近自然语言,全局函数则是例外,可以在任意位置直接使用。本文按函数类别逐一展开,配合实用示例帮助理解每个函数的实际用法。


目录

  1. Bases 与函数的关系
  2. 前提条件与版本要求
  3. 函数的两个使用场景:筛选与公式
  4. 全局函数
  5. 任意类型函数
  6. 日期函数
  7. 字符串函数
  8. 数字函数
  9. 列表函数
  10. 链接函数
  11. 文件函数
  12. 对象函数
  13. 正则表达式函数
  14. 常见问题与使用建议

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>") 返回 "&lt;b&gt;重要备注&lt;/b&gt;",原本的 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(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 转换为 1false 转换为 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、空列表、nullfalse 是假值(falsy)。

例如:42.isTruthy() 返回 true0.isTruthy() 返回 false"笔记".isTruthy() 返回 true"".isTruthy() 返回 false

isType()

any.isType(type: string): boolean

如果该值属于指定的类型,则返回 true。支持的类型名称包括 "string""number""boolean""date""list" 等。在对混合类型的列表进行处理前,可用此函数先筛选出特定类型的元素。

例如:"笔记标题".isType("string") 返回 truetrue.isType("boolean") 返回 true2026.isType("number") 返回 true

toString()

any.toString(): string

返回任意值的字符串表示形式。数字、布尔值等非字符串类型在与字符串拼接或用于字符串函数之前,通常需要先用此函数进行转换。

例如:2026.toString() 返回 "2026"


6. 日期函数

日期函数作用于日期和时间类型的值。日期值可以来自笔记属性中的日期字段,也可以由 now()today()date() 等全局函数生成。日期之间的大小比较可以直接使用 >、<、== 等运算符,更复杂的时间段运算可参考官方文档的日期运算部分。

字段

日期对象有以下可直接访问的字段:

字段类型描述
date.yearnumber日期的年份
date.monthnumber日期的月份(1–12)
date.daynumber日期的日
date.hournumber小时(0–23)
date.minutenumber分钟(0–59)
date.secondnumber秒(0–59)
date.millisecondnumber毫秒(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.lengthnumber字符串中的字符数

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.lengthnumber列表中的元素数量

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.mtimefile.hasTag() 等文件函数。

linksTo()

link.linksTo(file): boolean

检查该链接所代表的文件是否包含指向 file 的内部链接,若是则返回 true。这个函数可以用来构建基于链接关系的筛选逻辑。


11. 文件函数

文件函数作用于仓库中的文件对象。在 Bases 的筛选和公式中,每条记录本身就代表一个文件,可以通过 file. 前缀直接访问以下字段和函数,无需额外转换。

字段

以下字段可直接用于文件对象:

字段类型描述
file.namestring此文件的完整名称(含扩展名)
file.basenamestring不含扩展名的文件名称
file.pathstring相对于仓库根目录的完整文件路径
file.folderstring父文件夹的完整路径
file.extstring此文件的扩展名
file.sizenumber此文件的大小,以字节为单位
file.propertiesobject此文件的笔记属性集合
file.tagslist此文件的所有标签,包括行内标签
file.linkslist此文件中的所有内部链接
file.ctimedate此文件的创建时间戳
file.mtimedate此文件最后一次修改的时间戳

这些字段覆盖了日常使用中最高频的文件元数据。file.ctimefile.mtime 属于日期类型,可以直接使用日期函数进行格式化或比较;file.size 属于数字类型,可用数字函数处理;file.tagsfile.links 属于列表类型,可用列表函数操作。

file.asLink(display?: string): Link

将文件对象转换为一个 Link 对象,在视图中渲染为可点击的内部链接。可选提供 display 参数自定义链接的显示文字。

例如:file.asLink() 生成一个以文件名为显示文本的链接;file.asLink("查看详情") 生成一个显示文本为「查看详情」的链接。

file.hasLink(otherFile: file | string): boolean

如果该文件包含指向 otherFile 的内部链接,则返回 trueotherFile 可以是另一个文件对象,也可以是字符串形式的文件路径。

例如:当「项目总览」这个笔记中有指向「阶段一计划」的链接时,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 变更为 isTruthyto_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 指向包含该嵌入语法的外层笔记,可以借此实现与当前笔记内容关联的动态视图——这是在日记模板或项目笔记中内嵌关联任务列表的常见做法。