Add the `custom-dailynote-yyyyMMdd` attribute when creating a dailynote doc
frostime opened this issue · 19 comments
创建日记的时候为日记文档添加 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:加了属性之后,之前的文档怎么办?
社区开发者会解决,目前我在今日笔记里面已经了遍历过去的日记,并补充属性的功能。这些总会有办法的——前提是你要有这个属性。
支持
支持一下,很好的想法,很棒的界面
爱来自思源😘
支持
支持
支持。
在 logeseq 那边,由于“日记”的统一性,所以在实现日记流等功能方面是非常方便的,因为所有日记都是 yyyy-MM-dd 格式的文档。
思源则是太灵活了,缺少一个系统级的约定,以至于日记流的一些增强性的功能,不是那么好实现。
用属性的方式,对于需要的用户来说,可以实现想要的功能,对于不需要的用户来说,这也是一个不知道存在的玩意,完全没影响。
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不太行,假如只使用官方的创建日记功能确实如此,但我们需要想象一些比较奇妙的方向,比如我们需要创建一个过去或未来的日记。
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不一样。比如有的人用顶栏日历这样的工具,创建了几天前的日记呢?让每一个日期,都有其对应的文档,好过一些系统级的内容。
假如用创建时间,那调整了以后,文档路径和相关内容都需要调整,但是用自定义属性只需要针对这个文档做一次调整,关联关系都会保留下来。
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不太行,假如只使用官方的创建日记功能确实如此,但我们需要想象一些比较奇妙的方向,比如我们需要创建一个过去或未来的日记。
如果需要创建一个过去的或者未来的日记,其实也可以修改文件时间属性来达到,但是这是一个完全客制化的属性日记吗,那么两个属性分开比较好,比如一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不加时间戳很难应对多对一的情况。
就比如有的人,他的日记模板是
/<year>/<month>
,一个月的日记全放在一个文档里。 那这时候你想要查询某一天的日记对应的文档要怎么办?比如这种
文档创建于一个月1号,但是后面每天 Alt + 5 都会打开这个文档。
即使这样我也觉得应该是两个属性,而不是直接一个custom-dailynote-yyyymmdd,一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?以后统一调用怎么办呢,还需要正则屏蔽日期吗
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不加时间戳很难应对多对一的情况。
就比如有的人,他的日记模板是/<year>/<month>
,一个月的日记全放在一个文档里。 那这时候你想要查询某一天的日记对应的文档要怎么办?
比如这种
文档创建于一个月1号,但是后面每天 Alt + 5 都会打开这个文档。即使这样我也觉得应该是两个属性,而不是直接一个custom-dailynote-yyyymmdd,一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?以后统一调用怎么办呢,还需要正则屏蔽日期吗
设置成 custom-dailynote
然后sql查询 A.name = 'custom-dailynote'
和 设置成 custom-dailynote-yyyymmdd
然后 sql 查询 A.name like 'custom-dailynote-%'
没有什么特别的区分。
更重要的是,attr name 里有时间戳,可以应对我前面提到的多对一问题;如果统一设置成 custom-dailynote
,那你每天更新日记的时候这个属性就会被覆盖一遍,你要怎么区分这个文档属于那几天的日记?
我再次之前确实考虑过另一个方案 custom-dailynote: 20231201, 20231202
这样通过 append 日期的方式来存时间,后来发现这么弄还不如直接在 attrname 里存时间,实现起来还简单。
如果需要创建一个过去的或者未来的日记,其实也可以修改文件时间属性来达到,但是这是一个完全客制化的属性日记吗,那么两个属性分开比较好,比如一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?
update本身会不停变动,不适合使用。
created是从id前面部分截取出来,改不了的。
即使这样我也觉得应该是两个属性,而不是直接一个custom-dailynote-yyyymmdd,一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?以后统一调用怎么办呢,还需要正则屏蔽日期吗
需要怎么样统一调用?以思源的sql查询语法来看,指定日期查询为custom-dailynote-yyyymmdd,全部查询为custom-dailynote%,获取日记日期为select value …… "custom-dailynote%",还是很自然的
如果需要创建一个过去的或者未来的日记,其实也可以修改文件时间属性来达到,但是这是一个完全客制化的属性日记吗,那么两个属性分开比较好,比如一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?
update本身会不停变动,不适合使用。
created是从id前面部分截取出来,改不了的。
即使这样我也觉得应该是两个属性,而不是直接一个custom-dailynote-yyyymmdd,一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?以后统一调用怎么办呢,还需要正则屏蔽日期吗
需要怎么样统一调用?以思源的sql查询语法来看,指定日期查询为custom-dailynote-yyyymmdd,全部查询为custom-dailynote%,获取日记日期为select value …… "custom-dailynote%",还是很自然的
如果两个查询在现在和将来调用的区别区别并不大的话,确实一个更方便,这是一个可能涉及所有日记的更改,我也是考虑到统一性这么说,因为我不明白这是一个属性字段还是属性字段的值,我更觉得比较适合为一个统一的字段赋上不同的值
但其实我觉得只需要增加dailynote属性,时间戳属性不需要再添加,毕竟文档本身已经有创建时间和最后修改时间的属性,想查询调出所有属性还需要用正则屏蔽后面的日期
不加时间戳很难应对多对一的情况。
就比如有的人,他的日记模板是/<year>/<month>
,一个月的日记全放在一个文档里。 那这时候你想要查询某一天的日记对应的文档要怎么办?
比如这种
文档创建于一个月1号,但是后面每天 Alt + 5 都会打开这个文档。即使这样我也觉得应该是两个属性,而不是直接一个custom-dailynote-yyyymmdd,一个dailynote属性,一个是日记日期属性,这样以后联合查询会更方便,custom-dailynote-yyyymmdd使得每个日记没有了日记属性共性?以后统一调用怎么办呢,还需要正则屏蔽日期吗
设置成
custom-dailynote
然后sql查询A.name = 'custom-dailynote'
和 设置成custom-dailynote-yyyymmdd
然后 sql 查询A.name like 'custom-dailynote-%'
没有什么特别的区分。更重要的是,attr name 里有时间戳,可以应对我前面提到的多对一问题;如果统一设置成
custom-dailynote
,那你每天更新日记的时候这个属性就会被覆盖一遍,你要怎么区分这个文档属于那几天的日记?我再次之前确实考虑过另一个方案
custom-dailynote: 20231201, 20231202
这样通过 append 日期的方式来存时间,后来发现这么弄还不如直接在 attrname 里存时间,实现起来还简单。
我的意思其实是,字段应该统一,而字段值可以千变万化,直接把字段值当成字段,会不会导致数据库列太多?也可能不会?属性字段在数据库里占有单独的一列吗
我的意思其实是,字段应该统一,而字段值可以千变万化,直接把字段值当成字段,会不会导致数据库列太多?也可能不会?属性字段在数据库里占有单独的一列吗
每个属性只会增加attributes表里的一行。
欢迎 PR。