Dataviewjs的奇技淫巧

Dataview 是 Ob 里很著名的一个插件,它提供了十分便利的数据查询功能

利用 Dataview 插件,可以且轻易地通过文件夹、标签等条件创建表格或是列表

但是相对于 Dataview 查询,Dataviewjs 更少人知道

Dataviewjs

Dataviewjs 是 Dataview 插件的高级功能,与 templater 一样,它也使用 javascript 语言

想要使用它也很简单,与 dataview 类似,只要在代码块前面加上 dataviewjs

```dataviewjs
js语句
```

下面介绍我发掘的一些用法

简单点的自定义查询样式

1

功能:显示文件、标签的数量

```dataviewjs
var i = [dv.pages().length,dv.pages(`"200-笔记"`).length,dv.pages(`"700-收集文章"`).length,
         dv.pages().file.etags.distinct().length]
dv.paragraph(`总共有 **${i[0]}** 个文件`)
dv.paragraph(`其中==笔记== **${i[1]}** 篇,==收集文章== **${i[2]}** 篇`)
dv.paragraph(`==标签== **${i[3]}**个`)
```

Pasted image 20220327190921

2

功能:显示文件的时间

```dataviewjs
dv.list(
	dv.pages(``)
		.filter(p=>moment(Number(p.file.cday)).get("year")==2021)
		.sort(p=>p.file.cday,'desc')
		.map(p=>moment(Number(p.file.cday)).format('yyyy-MM-DD')+' >> '+p.file.link)
)
```

这个就比较中规中矩了,只不过是显示了文件的创建日期而已

你可能会觉得“这有什么用,我用dataview创建列表不一样能显示创建日期吗,你这个就是浪费时间”

确实如此,用 dataview 可以更简单地做到这件事,但是按照自己的意愿来显示的更好看诶,总有人会喜欢折腾的(比如我)

3

功能:这是用来管理的我的收集箱的代码

```dataviewjs
for(let i of dv.pagePaths(`"100-Index"`).groupBy(p=>p.split("/")[1])){
	dv.paragraph(`### ${i.key}`);
	let a = dv.pages(`"100-Index/${i.key}"`).length
	dv.paragraph(`共有==${a}==篇`);
	dv.list(
		dv.pages(`"100-Index"`)
			.filter(p=>p.file.folder.split("/")[1]==i.key)
			.map(p=>p.file.link+' - '+moment(moment().diff(moment(Number(p.file.cday)),'days'))+'天' )
	);
}
```

这段代码将不同文件夹的文件分别展示,并且显示了文件的数量及存在时间,提醒我尽快处理它们

与其他插件联合

这里举个例子,有个插件叫 Obsidian Charts,它可以生成可交互的图表,包括饼状图、折线图、条形图等等

```chart
type: line
labels: [Monday,Tuesday,Wednesday,Thursday,Friday]
series:
 - title: Title 1
   data: [1,2,3,4,5]
 - title: Title 2
   data: [5,4,3,2,1]
 - title: Title 3
   data: [8,2,5,-1,4]
```

```chart
type: pie
labels: [Monday,Tuesday,Wednesday,Thursday,Friday]
series:
 - title: Title 1
   data: [1,2,3,4,5]
 - title: Title 2
   data: [5,4,3,2,1]
width: 40%
labelColors: true
```

20220327_181903

虽然这个插件有给 dataview 的api,但我着实没搞明白:thinking:

不过这并不碍事,我自有一套骚操作:hugs:

```dataviewjs
let la = Array()
let da = Array()
for(let i of dv.pages().groupBy(p=>p.file.folder.split("/")[0]))
{
	la.push(i.key);
	let n = dv.pages(`"${i.key}"`).length;
	da.push(n);
}

dv.paragraph(`\`\`\`chart
type: pie
labels: [${la}]
series:
- title: none
  data: [${da}]
width: 50%
legendPosition: left
labelColors: true
\`\`\``);
```

这是个展示各个文件夹里文件数量饼图的代码

原理也很简单,就是写了个模板然后往里套数据,像上面的例子中,实际渲染的文本是

```chart
type: pie
labels: [000-HomePage,010-Mine,100-Index,200-笔记,210-课程,400-汇总,500-附件,600-日常,700-收集文章]
series:
- title: none
  data: [47,34,8,170,81,40,1,58,145]
width: 50%
legendPosition: left
labelColors: true
```

我觉得这是个很神奇的现象,dataviewjs 先渲染出上述文本,然后 obsidian-charts 再把这一段文本渲染成了饼图

依此原理,我们甚至能自动生成每月笔记数量的折线图

```dataviewjs
var y = "2022"
var m = Array(12).fill(0).map(function(v,i){return i});
var d = [31,29,31,30,31,30,31,31,30,31,30,31]

for(let i of m)
{
    var n = Array(d[i]).fill(0).map(function(v,i){return i+1});
    var data = Array(d[i]).fill(0);

    for(let j of dv.pages(`"200-笔记"`).filter(p=>String(p.file.cday).split("-")[0]==y && String(p.file.cday).split("-")[1]==i+1).groupBy(p=>String(p.file.cday).split("-")[2].slice(0,2)))
         data[j.key-1] = dv.pages(`"200-笔记"`).filter(p=>String(p.file.cday).split("-")[2].slice(0,2)==j.key).length;

    if(data.every(p=>p==0))
        continue
    dv.header(4, i+1+"月");
    dv.paragraph(`\`\`\`chart
type: line
labels: [${n}]
series:
- title: 200-笔记
  data: [${data}]
labelColors: true
\`\`\``)
}
```

这总算是个非常实用的功能了

通过这种用法,也许能写出根据标题自动生成 mermaid 的代码

直接使用 Ob 的插件 API

这是偶然听群友提到的,经过探索后发现像dataview、templater、quickadd等可以用 js 的插件能够调用 Ob 给插件用的 API

简单来说就是,本来给插件用的函数,可以通过以上插件给我们调用

比如以下调用了可以读取文件内容的 app.vault.readRaw 函数

```dataviewjs
const term = "日常记录"
const files = dv.pages(`"600-日常"`).filter(p=>String(p.tags).includes("日记")).sort(p=>p.file.name)
const b = files.map(async function(p){
    var x = await app.vault.readRaw(p.file.path);
    x = x.split("\n### ").filter(p=>p.slice(0,term.length)==term)[0];
    dv.paragraph("## "+p.file.name+"\n\`\`\`ad-note\ntitle: DailyNote\n"+x.slice(term.length)+"\n\`\`\`");
}
)
```

这样就集合了所有日记固定标题下的内容(顺便还展示了 Dataview 联合 Admonition 呢)

结束语

总之,dataviewjs 带来了更高级的数据分析或是自动渲染,这是个很有趣的功能

另外,这是我写过的第一篇文章,本人的 javascript 也是边用边学的,文章的语言或是一些代码可能写得很烂,也许折腾的成分大于实用性,因此希望能够以这篇拙劣的文章来抛砖引玉,吸引一些大佬分享自己的用法

70 个赞

羡慕, 看的想学js自己写。。。。。。

3 个赞

甚至可以调用第三方天气API用Dataviewjs画表格 :yum:

10 个赞

太强了!
请教一下,我在yaml区记录了每天的花费,如下:

第一天的yaml数据:
消费:
    午餐: 19
    晚餐: 25
    买菜: 10

第二天的yaml数据:
消费:
    午餐: 19
    晚餐: 25
    饮料: 3

但消费这个对象下面的子对象是不固定的,今天可能有买菜的开销,明天可能就没有了,或者多了个其他类型的。
我想每天统计“消费”这个对象下面所有子对象的数值之和该怎么写呢?我试过dataview的语法发现没法实现,然js不熟悉,还望赐教!

你想要什么样的统计呢,是每个笔记单独统计还是单列一个笔记用来统计

感谢:pray:不用了,方才已经试出来了

大佬,求问怎么在dataviewjs代码里获取到yaml中的键值对的值

hhh这个问题今天下午刚好试出来

test: get
dv.paragraph(dv.pages('你的路径').test.values[0])

不过如果是单文件的话可以直接使用

dv.page('文件路径').test

谢谢大佬!单独这样写确实可以(图中第一行),但是写到fliter里面以后就报错,是为什么呢(我的需求是找出所有yaml中ddl的值为today的页面)


欸,报错说的是toString函数未定义,能看一下你这个ddl的格式吗

感觉应该不是ddl格式的问题,因为前面第一行代码的DDL.toString()能用
image

filter里面那个==0的
前面的就是距离时间,那里改成大于3小于7就行了,刚出门,电脑不在身边,你尝试一下能不能成功

可以!!!谢谢大佬!!!如果我要列出ddl距离今天大于三天小于七天的文件应该怎么改呀,求教

奇怪,手机端好不方便啊,不小心把回复变成修改前面的回答了

不是很懂js里怎么写同时满足两个逻辑关系的情况,应该用&&吗?(之前回复的代码我先贴上,方便大家查看)

dv.list(dv.pages(``).filter(p=>moment(Number(p.DDL)).diff(moment(),'days')==0).map(p=>p.file.link))

是的,前面复制一份放到 && 后面作比较

可以了!非常感谢!!!

谢谢大佬!有用!

老哥,我在B站看到你的天气视图了:joy:,发现原来之前还关注过你