数据库的方式管理笔记-dataviewjs分享

dataview 对markdown笔记进行解析,使得提取笔记信息变得非常方便,可以方便的结构化展示内容,对一些不会代码的人不友好,我就分享自己的应用场景和写下的代码,供大家参考

我受到一部分他人的启发,用数据库的方式显示内容

视频介绍

4 个赞

单文档内的列表属性统计

首先是最简单的统计功能 ,比如说 我看牙医花了多少钱,这是在当前页面里 列表统计

左边是预览效果,右边是源码模式

重点是在 在每个列表里面增加 [price:: ] 里面的名称可以变化,但是要 英文开头,不要有空格,最多用下划线连接(就是js的变量名称要求, 其实可以有空格,dataviewjs会转化)

源码内容

    ```dataviewjs
    let sum=0
    dv.current().file.lists.map( t => sum+= t.price ?? 0)
    dv.el("b", "总实际花费(扣除医保): "+sum +" 元")
    ```
2 个赞

第二种方式,在不同的 md 文件里面 对 tasks/list 进行汇总

这里是 利用了 tags 对文件汇总,提取 #健身 这个大标签, 把 task 中有 的 #健身/健身环 子标签提取出来,再获取 dur:: 25 min 的属性值,进行汇总

代码展示


    ```dataviewjs
    const pages = "#健身"
    
    
    const re = /#(.+?)(?=\s)/g //去标签
    let fitTime=dv.duration("0 s")
    let fitCount =0
    const list = []
    
    dv.pages(pages) .sort(k => k.file.cday, 'desc').map(k => 
        k.file.tasks.filter(t => t.text.includes(pages))
          .map( t =>{ 
            list.push( [k.file.link, t.tags  ,  t.text.replace(re,"").replace(/\[.*\]/,"").trim(), t.duration ?? t.dur ?? ""  ])
          fitTime =  fitTime.plus(t.duration ?? t.dur ?? dv.duration("0 s"))
          fitCount +=1
          } 
    ))
    
    dv.table(["日期", "项目","内容", "持续时间"], list) 
    
    dv.el("b", "总运动时间: "+fitTime.shiftTo('hours').hours.toFixed(2) +"h ,运动次数 "+ fitCount)
    ```
2 个赞

第三种结构化显示,显示 该md文件被哪些文件引用

首先也是通过 tag 聚合,十分通用,把括号里 #GTD/03项目 改成你需要的标签即可

    ```dataviewjs
    for (let group of dv.pages("#GTD/03项目").groupBy(p => p.file.folder)) { 
        dv.header(3, group.key); 
        dv.table(["Name", "Inlink", "修改时间"], 
            group.rows 
                .sort(k => k.file.mtime, 'desc') 
                .map(k => [k.file.link, k.file.inlinks, k.file.mtime])) 
    }
    ```

这些本来可以不用这么复杂,我为了更加醒目,做了一些修改
比如 k.file.folder 改成 k.file.folder.split("-")[2] 因为我的文件路径是 03-task/02-work 就化简为 work

k.file.inlinks 改成

dv.array( k.file.inlinks.map((k)=>{
            const q = dv.page(k.path)
            return   "#"+q.file.folder.split("/")[0].split("-")[1] + " [["+ q.file.name +"]]"
            })).filter( (k)=> !k.includes("#Task"))

因为 我还想知道 被引用的md文件属于我的哪个顶层文件夹,是 输入 还是 输出 还是 成果,如果是 任务 就不显示,用 #更加显眼,不是真的标签

完整代码

    ```dataviewjs
    const pages = "#GTD/01重要"
    
    dv.table(["Name", "folder","Inlink", "修改时间"], 
        dv.pages(pages) 
            .sort(k => k.file.mtime, 'desc') 
            .map(k => [k.file.link, k.file.folder.split("-")[2] ,   dv.array( k.file.inlinks.map((k)=>{
            const q = dv.page(k.path)
            return   "#"+q.file.folder.split("/")[0].split("-")[1] + " [["+ q.file.name +"]]"
            })).filter( (k)=> !k.includes("#Task"))
             , k.file.mtime])
    ) 
    ```
2 个赞

这个不错,套用改下,用来统计阅读时长

因为JavaScript的教程繁多,眼花缭乱,所以向您提问请教:
要想达到像您这样使用dataviewjs的程度,您建议需要提前学习什么课程/看什么书?
谢谢!

*背景:
本人无编程语言基础
纯靠阅读blacksmithgu官方文档学习了dataview的基本用法
很吃力进行到Query Language Reference部分
再往后就读不下去了T_T

1 个赞

hh,本身会一点js的基础语法就好了,推荐 菜鸟教程的js 。我也看 blacksmithgu 的教程学的,多看多用,需要用到某个函数的时候再查询。看到别人好的实现,尝试理解一下,我写这个代码也花了我半天思考怎么实现,所以想分享出来,给大家一点思路。

我这部分代码,大部分都是操作数组,所以会有函数式编程,也就是 map,sort,filter
然后不断调试, console.log(dv.current()) 看看解析后的数据结构里面有什么,

dataviewjs 是根据 js 的实现,所以 js 的方法在里面都可以用。我用下来,有两个不一样的点

  • 通过 dv.page() 获取到的不是js的普通数组,而是一个代理数组,在全程使用 dv的函数会自动解析,如果用js的方法的话,需要 数据.array() 再用 dv函数的时候需要 dv.array(数据) Data Arrays - Dataview 里面写的清楚,一开始不知道的时候,用 数据.values ,另一种从代理获取值的方式:joy:
  • 符合格式的日期会自动转换,日期和时间中间要加T
3 个赞

很好的实用案例。

1 个赞

task 属性展示

```dataviewjs
const pages = '#task'
const tags = '#task'

const list = []

dv.pages(pages).sort(k => k.file.mday, 'desc').file.tasks.map( t =>{
	t.visual =  t.text.replace(/\[.*?\]/g,"").trim()
	const f = dv.page(t.path)
	const date = moment().format("yyyy-MM-DD");
	const dur =  dv.date(date) - t.due
	const  sg = dur<0 ? 'in ' : 'out '
	const taskList= dv.el('div',"")
	dv.api.taskList([t],false,taskList ,dv.component)
	
	list.push([ taskList ,sg + Math.round(Math.abs(dur)/24/3600/1000) +" days" ,f.priority ?? "" ,f.file.name ])
  
  } 
)

dv.table(["Name","Due", "Priority","Page"], list) 

```

可以去掉 task.visual 表示显示的html,还可以用 html元素包裹,根据不同重要醒显示颜色,详细看下面链接
https://s-blu.github.io/obsidian_dataview_example_vault/20%20Dataview%20Queries/Colorcode%20tasks%20based%20on%20meta%20data/

t.visual =   t.text.replace(/\[.*?\]/g,"").trim()

测试文件

tags 只是为了获取要统计的文件

---
created: 2024-08-20T17:09
updated: 2024-08-20T17:38
priority:
  - normal
tags:
  - task
---
- [x] 测试 1  [due:: 2024-08-22] [scheduled:: 2024-08-21] [completion:: 2024-08-20T21:12]
- [x] 测试 2,这是一大段很长很长很长很长很长很长很长很长很长的文字  [due:: 2024-08-23] [scheduled:: 2024-08-21] [completion:: 2024-08-20T21:17]
- [ ] 测试 3 [due:: 2024-09-24] [scheduled:: 2024-08-21] 
1 个赞

还有一个问题,就是这个里面通过JS统计出来的这个数值还可以在别的地方被引动么。比如这里是牙齿消费的汇总,另一个页面是娱乐消费汇总。再建一个页面作为总汇总,这个总汇总可以把娱乐消费汇总和牙齿消费汇总统计好的,再进行相加么。


这种结果前面的点可以删掉么,我看国外博主解决方案是把这个参数调整了。

好像原理是删掉了开头三个字符么?我完全不懂js所以不知道原理。

抱歉,刚看到
这个点是 dataview 自动转化,如果是源数据是数组,就会变成列表格式。
不想要点,可以把数组变成字符串

不可以 ,dv.current 只是说当前页面,但是数据来源可以更换的,简单改一下就好

```dataviewjs

let sum=0
dv.page('"要统计文件的路径1"').file.lists.map( t => sum+= t.price ?? 0)
dv.page('"要统计文件的路径2"').file.lists.map( t => sum+= t.price ?? 0)
dv.page('"要统计文件的路径3"').file.lists.map( t => sum+= t.price ?? 0)
...

dv.el("b", "总实际花费(扣除医保): "+sum +" 元")
```

或者用标签统计,dv.pages('#生活 and #工作' ) 还可以添加时间限制,比如一个月内,要看你怎么保存数据,用 where 语句 限制

只通过定义来把数组变成字符串么。

也可以用css样式 list-style: none;

1 个赞

不好意思,又来了,把数组变成字符串复杂么:thinking:。css,我没有找到对应的代码,没成功。

很简单的, 搜 js 数组转字符串


数组变量 join,就可以了

感谢,晚一些我试试看。

非常感谢,受到了启发