Description
创建日记的时候为日记文档添加 custom-dailynote-yyyymmdd
属性
背景
长久以来 daily note 有一个很大的问题:无法方便的查询指定日期对应的日记,而随着插件系统日益发展,这已经越来越桎梏大家对 daily note 做一些功能优化了。
目前的查询方案非常复杂: 首先需要获取 sprig 模板,然后将模板的 now 替换成其他模板函数,再交给后端渲染获取具体的 hpath,然后再找后端查询指定 hpath 的文档。问题很明显:1) 非常麻烦 2) 一次只能查询一个 3) 性能开销大。
最近这两个版本,alt + 5 来 create daily note 的工作流发生了变化:变成了 1) 后端创建文档 2)返回文档 ID 3)前端调用接口来打开文档。由于流程的变化,现在我们可以以非常简单的方案来解决上面提到的问题:在获取到日记的 ID 后,为文档添加一个自定义的属性。
具体方案
-
整体思路:为 yyyy-mm-dd 创建的 dailynote 增加一个自定义属性
custom-dailynote-yyyymmdd: yyyymmdd
(或者和 created 等字段保持一致yyyymmddsshhmm
也行) -
实现方案:在
app/src/util/mount.ts
的 fetchNewDailyNote 函数中,增加一行代码,来添加这个属性。下面是我在自己插件里实现的export function formatDate(date?: Date, sep=''): string { date = date === undefined ? new Date() : date; let year = date.getFullYear(); let month = date.getMonth() + 1; let day = date.getDate(); return `${year}${sep}${month < 10 ? '0' + month : month}${sep}${day < 10 ? '0' + day : day}`; } export function setCustomDNAttr(doc_id: string, date?: Date) { let td= formatDate(date); let attr = `custom-dailynote-${td}`; //例如 custom-dailynote-20231203 let attrs: { [key: string]: string } = {}; attrs[attr] = td; serverApi.setBlockAttrs(doc_id, attrs); } /** * 打开指定的笔记本下今天的日记,如果不存在则创建 * @param notebook_index 笔记本的 index */ export async function openDiary(notebook: Notebook) { //...省略 let dailynote = await serverApi.createDailyNote(notebook.id, appId); //...省略中间部分 //设置日记日期的自定义属性 setCustomDNAttr(dailynote.id); }
Line 13 in a75abfb
只需要加这么几行代码,设置一下属性,就可以了。
好处
1. 方便查询
直接的好处就是,现在我们可以用非常统一的方式,来查询任意范围、任意时刻的 daily note 了。
2. 解决多对一的情况
而且,这个方案也能有效地解决日记多对一的情况。比如有的人可能把日记的模板设置为 /daily note/{{now | date "2006/01"}}
。这样就导致了一整个月的日记全部放在一个文档里。
而有了上述方案,可以在单个文档中跟踪整个月的日记记录,只需要在查询的时候加一个 distinct 就可以应对多对一日记的查询。
3. 便于后面插件做进一步优化
有了这个属性,后面流式日记、自定义查询等各种优化实现起来就方便多、也会更加节省性能。
Q&A
这个提议之前提过一次,然后被 D 否决了,我这里预先回答一下可能会遇到的 battle。
Q: daily note 从设计上就是一个文档,不应该被特殊对待
这个观点本身自相矛盾,如果 daily note 应该和别的普通的文档完全一致的同等对待,那就连 alt + 5 都不应该实现。
软件内 daily note 事实上已经有特殊待遇了,在这种情况下非要坚持什么「daily note」就是一个文档,我觉得是掩耳盗铃。
退一步,就算认为添加了一个属性之后 daily note 就和别的文档地位不平等了——那又怎么样?
计算机里一个基本的哲学理念是合适的透明。如果你看不到、用不到,那就等于不存在。对于那些不会用到以后插件提供的高级功能的人来讲,多一个属性会带来什么奇怪的变化吗?他们思源的性能会因为一年多了 365 个文档属性而变得特别拉跨吗?如果不会的话——那加不加属性对他们而言就是无感的,在他们眼中日记和其他文档就是平等一致的。
Q:加了属性可能不准确的,比如用 Alt+5 创建的日记也可以重命名为其他文档。
软件的实现者不应该考虑这种问题 —— 因为这属于 exceptional 的行为。我们不能为了一小部分用户奇怪的操作就驻足不前。
Alt + 5 已经明确是「创建日记」功能了,那么创建日记后还重命名、移动文档的用户应该有「这是非正常使用方式」的自知之明。
我们真正要考虑的应该是怎么优化那些正常使用软件的用户的体验,而不是去关心那些不正常使用软件的用户的体验——错的是他们的使用方式,而不是软件。
Q: 插件自己遵循这个规范,不改本体可不可以?
不可以,如果本体不遵守这个规范,那么插件规范了个寂寞。问题的核心在于,要建立一个官方认可的统一协议,以后所有的日记相关插件都遵守这个协议。
Q:加了属性之后,之前的文档怎么办?
社区开发者会解决,目前我在今日笔记里面已经了遍历过去的日记,并补充属性的功能。这些总会有办法的——前提是你要有这个属性。