去年三月,我发布了我在少数派的第一篇文章,也留下了我对如何发掘 Notion 数据库潜力的相关经验:使用中转数据库和模板建立跨数据库链接,让函数实现跨表查询从而提高多数据库的联动能力。如果还未了解该文章,可以在这里看到:
经过一年的迭代,Notion 也推出了更多自动化能力,使我的工作流降低了对函数字段的高度依赖,同时也大幅减少了函数运算在页面加载时会带来的长时间卡顿。此消彼长之间,我的项目管理系统日趋完善,也促成了本次以自动化为主题的分享。
文中使用的示例可于此处获取副本。
(P.S. 示例中使用的项目名称、历程名称、历程详情均为AI生成。本文撰写过程中没有一名建筑师、甲方、用户受到伤害。)
需求的开端
在我所在的建筑行业中,对三维模型和图纸文件的反复修改已是家常便饭,而版本控制一直是建筑设计工作流中缺失的一环。虽然白纸黑字的书面记录,并不能完备地解决该问题,但它仍能带来一个实用的益处:当领导质疑某项设计决策的原因时,我至少能迅速甩出之前的工作日志并理直气壮地回复:这个改不了!
至此,我便有了要将项目的工作历程留下书面记录的决心。
Notion 自动化的类型
在正式介绍我的工作流之前,有必要先厘清 Notion 目前林林总总的自动化功能,以及其各自的特点。
功能名称 | 运作方式 | 调用函数 | 定义变量 | 计算过程 | 操作性质 |
---|---|---|---|---|---|
按钮块、数据库按钮字段 Button |
通过主动点击,执行预设操作 | 支持 | 支持 | 后台 | 主动点击 |
数据库函数字段 Formula |
通过预设函数公式,保持计算结果实时更新 | 支持 | 支持 | 前台 | 自动计算 |
数据库汇总字段 (简化版函数字段) Rollup |
通过预设汇总方式,保持计算结果实时更新 | 不支持 | 不支持 | 前台 | 自动计算 |
数据库模板重复 | 周期性自动创建预设页面 | 不支持 | 不支持 | 后台 | 自动创建 |
数据库自动化 Automation |
监听以下事件,执行预设操作 ①页面指定字段的编辑 ②页面创建 ③指定时段周期 |
支持 | 支持 | 后台 | 自动计算 |
Notion 集成 (关联第三方服务) Integration |
通过第三方服务来间接实现的自动化,如苹果的快捷指令、Make等 | 无 | 无 | 后台 | 取决于第三方服务 |
函数字段是前台计算,在相关字段编辑、页面增减、页面加载时触发,计算期间页面将无法操作;数据库自动化为后台计算,仅在指定字段编辑、页面增加、周期运行时触发,计算期间不影响其他操作。——这恰恰是影响使用体验的决定性因素。
虽然复杂的数据库自动化实质上也是依赖函数公式来计算,但其与函数字段不同的运作机制造就了截然不同的体验。为确保显示结果的实时性和准确性,函数字段会在每次页面加载时强制重新计算,前台计算的特性拖累了页面的加载效率,一旦公式内涉及的字段发生修改时,用户也必须等待计算完毕后才能进行下一步操作。相比之下,数据库自动化只会在后台默默监听,按需启动,保持 Notion 操作界面的响应性。当然,函数字段也并非一无是处,其「实时性」的结果天然比数据库自动化更值得被信赖,但不同的特性决定了我们应因地制宜选择恰当的工作流。因此,本文将着重探讨以按钮和数据库自动化等后台计算为主要手段的项目管理实践。
回望数据库自动化首次实装时,在少数派去年完结的 Notion: All in One 付费栏目 中,栏目作者在其中一文里提到数据库自动化的触发条件有较大的局限性:
- 触发器中的多个触发条件只能为
或门
关系(任意条件成立则触发),无法设置与门
关系(所有条件全部成立才触发)。 - 触发器中的字段监听能力有限,缺乏自定义筛选手段。
而 Notion 最近一年半的更新则另辟蹊径地弥补了该不足,除了增加 与门
选项以外,还支持将触发器的监听范围与特定的数据库视图绑定,使监听条件能直接利用上 Notion 视图完善的过滤机制,从而充分拓展了自动化的设定能力。


需要注意的是,作为后台自动化,数据库自动化无法被其他任何原生自动化触发。这其实是官方有意设计的「安全阀」,目的是避免「『页面A的修改』触发了『修改页面A的规则』」这种无限自循环的情形。但以上限制并不适用于第三方服务,所以利用好第三方的「外力」也将帮助我们打造更丝滑的自动化工作流。
基础框架
有了如此丰富的自动化能力基础,想要搭建一个复杂的、高度自治的项目历程管理系统,我们需要先明确这个系统所需的架构,其中应包括:
- 项目库——记录每一个项目。其包含的主要字段应有:项目名称(标题)、关联历程、关联周记、中转库。

- 历程库——记录每一项具体的工作内容。其包含的主要字段有:历程名称(标题)、历程时间、所属项目、所属周记、中转库。

- 周记库——周期性的历程展示界面。因为行业的性质,一项工作有时足以撑满两三天,所以我使用周记而非日记,如果有兴趣参考该架构,使用更适合你任务频率的周期设置即可。其包含的主要字段包含:周记名称(标题)、当周首日(日期)、当周年份(数字)、当周周数(数字)、当周日期(日期)、涉及项目、涉及历程、中转库。

- 中转库——只包含一个页面,将前三个数据库的 Relation 字段关联到本数据库,并通过前三个数据库的模板使每一页都与中转库该页面自动关联。

需要明确的是,这四个数据库中的关联字段皆为双向关联(即在任一页面填入关联项时,被关联项的相应字段也会自动填入该页面,形成双向关联关系)。将上述数据库的字段妥善创建后,其关联关系如下图所示。

建立自动化流程
想做好自动化,需要对数据录入点和完整的数据传递流程有清晰的认知。
单一数据库的自动化通常有着简单的数据传递链,而当我们有多个数据库主体时,库与库之间的复杂联动就很难平铺直叙地在脑海中完成构筑了。在创建这些模板、函数字段和自动化流程之前,我们需要先梳理哪些数据是需要我们手动录入的,哪些是可以交给自动化代为完成的,同时,自动化操作的触发又将依赖于什么数据,自动化的执行需要部署在哪一个数据库中,对这些框架有了基本的认知之后,我们才能更加得心应手地搭建好它们。
项目数据库
让我们从最容易的项目数据库开始:通常来说,由于创建新的项目页面是一个低频次且难以预测的行为,所以它将重度依赖手动创建。在输入项目名称的同时,我们也需要让页面自动关联到中转数据库,这个步骤可以借助模板来实现。设置好模板后,也别忘了将其设置为默认模板以便创建时自动调用。

如果说你的项目有相对固定的创建周期,那么你可以设置 重复频率
实现周期性自动创建,其是否启用不会影响我们后续的搭建流程。

历程数据库
历程的页面创建
历程数据库扮演着桥接项目库和周记库的角色。其中的每一页不仅需要和项目页面保持从属关系,也需要通过历程时间匹配到相应的一个或者多个周记页面。首先我们仿照项目库建立一个默认历程模板,关联中转库的同时,也应在创建时填入当前时间作为其历程开始时间。

由于历程与项目之间的从属关系是相对稳定的,故我们可以选择在项目库部署一个 创建历程
按钮,点击时将套用历程模板并使创建的历程页面自动关联上按钮所在的项目页面。

同时,该历程页面也需要自动关联上周记页面。由于我们模板中默认的历程开始时间是「现在」,所以我们可以直接选择周记数据库中按时间由早到晚排序的最后一个页面(也就是「当周」)即可,具体的函数写法在查重一文中已有介绍,此处不再赘述原因。
在此之后,我们也需要让创建的页面自动打开,便于我们手动输入历程名称。至此,创建历程页面的按钮就部署好了。
/* 当周周记 */
prop(当前页面).prop(中转库).first()
.prop(周记库).sort(current.prop(当周日期)).last()


历程的完成状态
回到历程数据库,历程时间
目前还缺少一个结束时间点,我们可以新增一个 状态
字段用来标记历程的完成情况,同时新增一个 完成
按钮用来快速添加结束时间,并将状态标记为「已完成」。
/* 历程时段 */
prop(当前页面).prop(历程时间).dateStart()
.dateRange( now() )

需要注意的是,随着时间的修改,我们需要同步调整该历程所关联的周记。虽说今日事今日毕是良好的工作、生活态度,但跨日或者跨周的任务安排也并不罕见,让数据库适应我们的日程安排习惯才是自动化所能带来的终极效益。
接下来,继续在自动化面板中添加新变量 历程→周记
,此处的函数较为复杂,其核心逻辑是:若历程时间和任意一周有时间重合,则应关联该周的周记。具体的判断标准是:「周尾晚于等于历程开始时间」且「周首早于等于历程结束时间」。计算完成后,用得出的结果替换掉 所属周记
字段即可。
/* 历程→周记 */
prop(当前页面).prop(中转库).first()
.prop(周记库).filter(
current.prop(当周日期).dateStart() <= prop(当前页面).prop(历程时间).dateEnd() and
current.prop(当周日期).dateEnd() >= prop(当前页面).prop(历程时间).dateStart()
)
.sort(current.prop(当周日期))

同理,项目和周记的关联关系,也会随着历程时间变化而调整。我们可以通过当前历程所属项目获取到该项目的所有历程,并进一步获取到每一项历程关联的周记,将这些「项目的历程的周记」汇于一处然后去重并排序就得到该项目应关联的所有周记页面。
/* 所属项目 */
prop(当前页面).prop(所属项目).first()
/* 项目→周记 */
prop(当前页面).prop(所属项目).first()
.prop(关联历程).map(current.prop(所属周记))
.flat().unique()
.sort(current.prop(当周日期))

完成
按钮的完整执行步骤如下:


历程的时间调整
最后,不论是在 Notion 又或是 Notion Calendar 中,难免会有直接手动修改历程时间的情况,所以我们仍需对历程时间的变化保持监听,用来自动更新该历程应关联的周记页面,和历程所属项目应关联的周记页面。该自动化的函数结构与前述的 完成
按钮的后半部分基本相同,可以直接把函数复制过来,将所有的 当前页面
修改为 触发器页面
即可。