Bases基础用例:显示同文件夹内的笔记

概述

Obsidian 的 Bases(数据库)版本 1.9.10 已经发布,相信很多人会好奇——它有什么用?

本文用一个简单的例子来介绍它的用法,同时也作为“一步步跟着实现”的基础教程。

效果

我们先看数据库实现的效果:


该库为 Kepano 的示例库

这个 Bases 的作用很简单:显示出和当前笔记相同文件夹的其他笔记
非常适合你在浏览笔记时,快速查看相关的其他笔记。

实现

首先,在文件浏览器中右键,创建新的 Base 文件:
250819_Bases基础用例:显示同文件夹内的笔记-img-250819_103859.webp

创建完后,为它取一个名字,例如 base-SameFolder

然后你会看到 Bases 的基础状态:
一个表格,包含你库中的所有文件。

接下来,我们要认识到最重要的两个基础概念:筛选属性

概念

数据库最重要的部分在最上方的操作区域,包含:
250819_Bases基础用例:显示同文件夹内的笔记-img-250819_104236.webp

左上方:

  1. 视图
  2. 结果(包括导出 CSV、结果数量限制等功能)

右上方:

  1. 排序
  2. 筛选
  3. 属性
  4. 新建

我们会先聚焦在最重要的 Filter 筛选器和 Properties 属性上。

筛选

筛选器,即定义“显示的条件”。

默认情况下所有文件都会被列出来,而过多的信息量等于无效的信息量
所以我们需要定义好自己希望看到的内容。

在这次的案例中,条件即「和当前笔记相同文件夹」。

属性

每个文件有自己特定的属性,属性可以用在“筛选”的条件,也可以作为“显示的信息”。
属性除了笔记最上方的 Properties 属性区域中的属性,还包含一些隐性的元数据,例如文件路径、文件所在文件夹等。

对于这次案例,我们需要获取到 文件夹 属性。

实践

特定文件夹

点击 Filter 按钮,会弹出筛选器的 UI。

我们打开 All views(对所有视图生效)筛选器,并且选择:
file | in folder 即“在特定文件中”。
250819_Bases基础用例:显示同文件夹内的笔记-img-250819_104755.webp

然后我们可以先手动输入一个文件夹(路径带有自动补全),查看效果:

可以看到,这样配置之后,已经可以显示来自特定文件夹的笔记了。
为你 Bases 最重要的第一步喝采! :partying_face:

公式:动态筛选条件

但是我们想要实现的目标是:显示和当前笔记相同文件夹的笔记。

总不能每次都手动修改文件夹路径吧?
所以,我们需要更动态的筛选条件。

首先,点击右侧的 </> 按钮,
250819_Bases基础用例:显示同文件夹内的笔记-img-250819_105126.webp

进入高阶筛选器的编辑界面:

250819_Bases基础用例:显示同文件夹内的笔记-img-250819_105158.webp

可以看到,这时候筛选条件变成了一条公式:
file.inFolder("References")

它的含义和刚才的筛选器完全一致:file 位于文件夹 Reference 内。

:bulb: 公式有点儿类似 Javascript 代码,但是相对简单,你可以通过先构建简单过滤器,然后切换成高阶过滤器的方式来进行学习。
更多资料也可以查看:

这里的 file 指代每一个进行检验的文件,如果符合条件,就列进结果中。
所以,我们下一步要做的是——把文件夹 Reference 换成实际的 当前笔记所在的文件夹

具体来说,把 "Reference" 替换成 this.file.folder
250819_Bases基础用例:显示同文件夹内的笔记-img-250819_105529.webp

你可以先这样修改,看看结果,然后我们再说理论部分。

关于当前文件

如果一切顺利,在输入完毕后你会看到当前 base 文件所在的文件夹的文件:


(可能只有它自己)

接下来我们就要介绍到 this 这个特殊的变量——
它代表“当前”的文件,但是这个“当前”取决于 Base 所在的位置。

举个例子,当前我们在主要编辑器编辑 Base,那么这个 base-SameFolder.base 就是当前文件。

但是,如果我们把 base 文件拖到侧栏,然后点击一下当前的笔记,事情就会发生变化——

当 Base 位于侧栏或者分屏编辑器时,this 代表的就是当前激活的文件

这是一个很重要的特性,也正是基于这个特性,我们才能实现“当前笔记所在文件夹的其他笔记”这个功能。

噢顺便一提,不知道你注意到了没,当你做到这里的时候,你已经实现了我们一开始想要完成的效果了 :wink:

恭喜! :tada:

原理和小技巧

原理上来说,我们最终的筛选条件:file.inFolder(this.file.folder)
即我们先用 this.file 获取到当前激活的笔记的“文件对象”,然后再通过 .folder 获取到它的文件夹信息。

这里有一个小技巧,你可以点击 Properties → Add Formula 添加公式属性:

输入 file. 后你会看到它具有的各种属性:
image

输入完整的 file.folder 时,就可以看到每个文件的该属性:
image

——这也是一个测试 bases 公式的实用技巧,多试试其他属性吧!

总结

这次我们尝试了:

  1. 创建一个新的数据库文件
  2. 添加筛选条件,来显示出我们想要的笔记
  3. 通过移动 base 到侧栏,来获得动态的筛选结果
  4. 同时,了解了基础的文件属性

希望这篇文章能作为你的 base 之旅的轻松起步,祝你玩得愉快~

Moi moi! ( ̄▽ ̄)ノ

资料

这里是一些相关资料,可以作为拓展学习。

Base 文档

Bases syntax - Obsidian Help
base 的基础语法,建议在实践完之后(或者之前)先查看该文档,获取扎实的基础知识。

Properties 章节,你可以看到笔记属性和文件属性的介绍;
Functions 页面,你可以看到关于公式/函数的介绍和应用。

示例库

kepano/kepano-obsidian
Kepano 分享的 Obsidian 示例库,他已经将库中的筛选都换成了 bases 数据库形式,你可以在里面学习到很多用法。

7 个赞

讲的很好,要是有视频教程,那就更完美了。

假如楼主每个电影笔记都有一句话影评,怎么把它提取出来,显示在bases列表中?

笔记内部的话,目前没办法。
除非你写进属性区内。

我写过一个 TP 脚本快速提取某个标题里的文本进属性区,感兴趣可以试试:

<%*
const noteContent = tp.file.content; // 获取当前笔记的内容
const maxLength = 150; // 设置概述的最大长度(通常博客描述在100-150字之间)

// 清理 Markdown 格式符号
function cleanMarkdownText(text) {
    return text
        // 提取链接标题:[标题](链接) -> 标题
        .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
        // 去除粗体:**文本** 或 __文本__ -> 文本
        .replace(/\*\*([^*]+)\*\*/g, '$1')
        .replace(/__([^_]+)__/g, '$1')
        // 去除斜体:*文本* 或 _文本_ -> 文本
        .replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '$1')
        .replace(/(?<!_)_([^_]+)_(?!_)/g, '$1')
        // 去除代码块:```代码``` -> 代码
        .replace(/```[\s\S]*?```/g, (match) => {
            return match.replace(/```[^\n]*\n?/g, '').replace(/```/g, '');
        })
        // 去除行内代码:`代码` -> 代码
        .replace(/`([^`]+)`/g, '$1')
        // 去除删除线:~~文本~~ -> 文本
        .replace(/~~([^~]+)~~/g, '$1')
        // 去除高亮:==文本== -> 文本
        .replace(/==([^=]+)==/g, '$1')
        // 去除标题符号:# 标题 -> 标题
        .replace(/^#+\s+/gm, '')
        // 去除引用符号:> 文本 -> 文本
        .replace(/^>\s*/gm, '')
        // 去除列表符号:- 项目 或 * 项目 或 1. 项目 -> 项目
        .replace(/^[\s]*[-*+]\s+/gm, '')
        .replace(/^[\s]*\d+\.\s+/gm, '')
        // 去除多余的空白字符
        .replace(/\s+/g, ' ')
        .trim();
}

// 查找「概述」标题下的内容
function getDescriptionFromContent(content) {
    const regex = /^##?\s*概述\s*\n([\s\S]*?)(?=\n##|\n#|$)/m;
    const match = content.match(regex);
    if (match && match[1]) {
        // 清理文本:去除空白行、多余空格和 Markdown 格式
        const cleanedText = match[1].trim().replace(/\n+/g, ' ');
        return cleanMarkdownText(cleanedText);
    }
    return null;
}

// 截断文本并添加省略号
function truncateText(text, maxLen) {
    if (text.length <= maxLen) return text;
    // 在最后一个完整的词处截断
    return text.substr(0, maxLen).replace(/\s\w+$/, '') + '...';
}

// 主流程
async function updateDescription(text) {
    // 清理 Markdown 格式符号
    const cleanedText = cleanMarkdownText(text);
    const truncatedDesc = truncateText(cleanedText, maxLength);
    const noteName = tp.file.title;
    const fileObj = tp.file.find_tfile(noteName);
    
    await app.fileManager.processFrontMatter(fileObj, (fm) => {
        if (fm["description"]) {
            // 如果已存在描述,提示更新
            new Notice("已更新笔记描述");
        }
        fm["description"] = truncatedDesc;
    });
    
    new Notice("已添加笔记描述");
}

// 开始处理
const description = getDescriptionFromContent(noteContent);
if (description) {
    await updateDescription(description);
} else {
    // 如果没有找到概述,弹出输入框让用户输入
    const userInput = await tp.system.prompt("未找到「概述」部分,请手动输入描述文本:");
    if (userInput) {
        await updateDescription(userInput);
    } else {
        new Notice("已取消添加描述");
    }
}
-%>

分享下我的用法:结合 Signynt/virtual-content插件,实现无侵入性的页内组件(效果同样是“显示文件夹内笔记”)


卡片视图:

首先和Moy的步骤一样,需要一个Base文件:


补充:排除当前文件
PixPin_2025-08-25_17-22-57
补充:不考虑子文件夹:
PixPin_2025-08-25_18-07-29

然后在virtual-content插件内新建规则:

通常还需要限制搜索数量(因为文件夹下匹配的文档数较多):
PixPin_2025-08-25_17-12-10

还有一个很好用的功能是:点击“新建”按钮就能直接在当前文件同层级新建文件了——
PixPin_2025-08-25_18-05-12

2 个赞

这个好,现在各种插件侵入笔记太烦了,被插件绑架了。 使用md的初衷就是纯净