基于数据库的全局属性可行性探讨

先说一个暴论:自定义属性对于普通用户没有使用什么价值,数据库才是普通用户的最终归宿。

自定义属性不支持中文名,这一条就可以把它枪毙了,还是让它在插件作者的手中发挥余热吧。

我们来讨论讨论基于现有数据库方案的全局属性可行性。

什么是全局属性

全局属性是 anytype 的数据库方案,详见 Anytype——思源数据库的指路明灯 - 链滴。简单来说,全局属性就是所有数据库共用属性,属性具有唯一性,一处修改,处处同步,达到属性复用的目的,一个块添加到多个数据库,这些数据库如果有同名属性 A,那么这个块就只有一个属性 A 值。

目前思源笔记不同数据库的同名属性是不互通的,就像你在多个 QQ 群可以有不同的昵称,这既是优点也是缺点,如果你只想有一个昵称,就会觉得很麻烦,需要一个个 QQ 群改过去。

全局属性方案 1

对于属性唯一性问题,最简单的解决方案就是一把梭哈,只保留一个“全局属性”数据库!把所有属性都塞到一个 json 文件里!其他数据库都是全局属性数据库的镜像数据库,新建数据库=新建视图,通过不同的视图来展示不同的属性。

这个方案需要对现有数据库的显示、操作等进行一定的修改。

显示方案的修改

需要将数据库名称栏取消,保留视图栏即可。因为所有的数据库都是全局属性数据库的镜像数据库,显示的是它的不同视图。

image

操作逻辑的修改

添加行的逻辑修改

不同的视图可以显示不同的属性列,但是如何对行进行限制呢?下面是数据库的一个视图的 json 定义,可以看到其中有个属性是 rowIds​,经测试 rowIds​和筛选操作无关,似乎是个预留属性,目前没起到什么作用,那么 rowIds​属性完全可以作为从全数据库中显示哪些行的依据。在新建数据库(=新建视图)的时候,视图的 rowIds​设置为空,当向视图中添加块的时候,进行如下操作:

  1. 如果块已经存在于全局数据库中,则将 rowId​加入到目标视图的 rowIds​属性中

  2. 如果块不存在于全局数据库中,则

    1. 向全局数据库中添加一行
    2. 将新增行的 rowId​加入到目标视图的 rowIds​属性中
  3. 如果添加的不是块,而是普通文本行呢?执行步骤 2。

    {
      "id": "20240305145356-a78x9ht",
      "icon": "",
      "name": "表格",
      "hideAttrViewName": false,
      "desc": "",
      "type": "table",
      "table": {
        "spec": 0,
        "id": "20240305145356-jkvhorr",
        "columns": [
          {
            "id": "20240220201428-she86q1",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220203146-trhlqnq",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240221125355-h02xmfr",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220201831-kb2ybyq",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220202627-8ttud4q",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220202413-gp2dgk9",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240221113912-7xwex9g",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220202707-oldswhq",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          },
          {
            "id": "20240220205140-zak4f3d",
            "wrap": false,
            "hidden": false,
            "pin": false,
            "width": ""
          }
        ],
        "rowIds": [
          "20241122122950-seuq0iy",
          "20241112092733-le5f8s2",
          "20240220201553-ezjsz1o",
          "20240220201651-dny3n04",
          "20240220201657-re0asqe",
          "20240220201704-1udbxtc",
          "20240221113424-zqw91jx",
          "20240301163132-8gs4bk2",
          "20240301163120-3z96swp",
          "20240221122431-1uh1rbl",
          "20240221122819-n1kzzs8",
          "20241112135653-2n4ien0",
          "20241112135730-aeyjttk",
          "20241112135754-m472bmu"
        ],
        "filters": [],
        "sorts": [],
        "pageSize": 50
      }
    }

添加列的逻辑修改

添加列时需要在弹出菜单中新增一个选项“选择全局属性”,点击后就可以将全局属性数据库的某个列添加到该视图。

image

全局属性方案 2

方案 1 保证了属性在工作空间内的唯一性,相当于你在多个 QQ 群全部实名制了,这时候有些小可爱就要问了:有没有可能在大部分 QQ 群中实名制,在一部分 QQ 群中使用不同昵称呢?这就是方案 2 要解决的问题。

方案 2 维持现在的一个数据库一个 json 文件,主要在 json 文件的读写上下功夫。

首先还是得内置一个“全局属性”数据库,这个数据库对于用户是隐藏的,用户能够操作的数据库就叫普通数据库吧。

全局属性数据库与普通数据库列的关联

在数据库的添加列菜单中增加“添加全局属性”、“选择全局属性”两个按钮:

  • 添加全局属性

    • 点击后在普通数据库和全局数据数据库中同时新增一个列,这两个列具有相同的 keyid
    • 在对这个新增列命名时需要对属性名进行校验,禁止与全局属性数据库中的已有列同名。
    • 将普通数据库中的所有行的 id 添加到全局数据数据库中
  • 选择全局属性

    • 从全局属性数据库中选择一个属性添加到普通数据库中,具有相同 keyid
    • 将普通数据库中的所有行的 id 添加到全局数据数据库中

image

全局属性数据库与普通数据库属性值的同步

在修改普通数据库的单元格时,如果普通数据库中具有全局属性,需要将修改后的值同步到全局数据库相同行中,再同步到其他普通数据库相同行中。

相同行的判断

每行的主键列单元格都有 blockID,让普通数据库和全局数据库的相同行具有相同的 blockID 即可。

image

方案对比

方案 方案 1 方案 2
数据保存 全部保存到全局 JSON 文件 内置全局属性 JSON 文件,其他数据库不变
特点 属性唯一 全局属性 + 数据库自有属性,比较灵活
主要改动 前端显示与操作逻辑的修改 后端读写的修改,需要同时读写多个 JSON 文件

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22370 引用 • 89532 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • YRJ0422 1 赞同

    非常支持改进,尤其是用了楼主的 Quicker 动作已经离不开了

    Clip20241122210638.jpg

    Clip20241122210750.jpg

  • 其他回帖
  • zxhd86 2 3 赞同

    这个方案最大的问题就是数据量大了之后会卡的离谱,毕竟思源是在一个没有索引、每次操作都要完全读取、反序列化、遍历、修改、序列化、重新全文写入的 json 上工作的……

    与其在 json 上苟延残喘,我建议全面转投 sqlite。这东西才算是未来可期,可以承载百万级数据量的属性和表格。

    现在的 json 在万行上就开始卡顿了,全部塞一起性能瓶颈只会来得更快。

    1 回复
  • 其实好几个是我提的哈哈哈

    其实还有一个改进思路是把 query 挂件做个升级,变得更简单易用,参考 obsidian 的 dataview

  • 我是小白,可能对大佬的内容理解的不是很透彻,方案一看起来改动更大且应该很难支持长期使用,对性能的要求也更高,我更倾向于方案二。对于方案二,是否也可以考虑一个全局属性一个 json 文件,不知道哪种方式对性能更有利。

    当然,如果可以接受不将一般属性和全局属性汇总显示的话,或许可以考虑改动更小的方案三,在目前的内置属性,数据库属性,自定义属性之上加一个全局属性,在块端查看全局属性。

  • 查看全部回帖