DataviewJS Snippet Showcase

#help

[Please let me know if more info is required]

I need a little assistance in writing an inline JS query to give me the number of orphan notes in my vault. I have a home page that gives me stats like inbox items, in-process items and so on. Attaching a reference image.

Orphan Notes JS Help

I have a reasonable knowledge on Dataview and have used the (inlinks) and (outlinks) concept to fetch as a table. But I need a number (the number of orphan notes) and nothing else, thus the inline dataviewjs requirement.

NOTE: dviqjs: is a custom prefix I have assigned for Dataview-inline-JS

I got into studying Norse mythology and history last year, which resulted in a ton of pages for various people, terms, what have you. I also imported a lot of Norse text and translations into Obsidian. It got a bit wide and crazy at times. Especially since a lot of info wasn’t sourced from the original text, but references to references.

So I wrote this footer to add to my notes, which makes sure that any links to the page from original (or translated) text gets highlighted if I haven’t already referenced it on the page. That way the original source material gets the spotlight rather than just relying on general backlinks, and whenever I see an “unlinked attestation”, I’ll click in on the note and see exactly what the source material said, which helps me fill out my knowledge about the topic.

Each page has the following at the end:

```dataviewjs
dv.view("00 Meta/Javascript/query_attestations")
```

And query_attestations contains:

let pg = dv.current();

if (dv.pages("#📖").where(b => b.file.outlinks.includes(pg.file.link)).where(b => !pg.file.outlinks.includes(b.file.link)).length > 0) {
    dv.header(2, "Unlinked attestations");
    dv.list(dv.pages("#📖")
        .where(b => b.file.outlinks.includes(pg.file.link))
        .where(b => !pg.file.outlinks.includes(b.file.link))
        .file.link
    );
}
4 Likes

I found out today a way to quickly see the values returned by DataviewJs. I don’t know if it has been shared here. But just in case it might help someone.
If you open the DevTools (CTRL+SHIFT+I) you have access to all DataviewJs’s commands. They are found by typing DataviewAPI in the DevTool’s Console. This way you can quickly see what’s right or wrong in your query.

Here’s an example:
image

15 Likes

I was searching high and low for two days for any way to audit all my YAML keys/fields in my vault and couldn’t find anything, so I went ahead and coded it myself. My implementation is simple, but I’ll probably use it as a launching point for other projects (and I’m hoping somebody else finds it useful, too!).

I keep one note with this query for reference so I can spot-check whether I have any keys or fields misspelled, capitalized differently, etc., since I hate to think something might get lost from my queries due to a typo. It’s both a blessing and a curse that you can put whatever you want in there!

I believe that, as long as you have the same versions of Obsidian (v0.14.15) and the Obsidian Dataview plugin (v0.5.36) installed that I do, you should literally be able to copy/paste this into a DataviewJS codeblock and it should just work for you…?

// Unique YAML Keys Audit
// Brought to you by Jocelyn Tuohy
// 2022.06.19
// Created using:
// - Obsidian (v0.14.15)
// - the Obsidian Dataview plugin (v0.5.36)

let uniqueKeyArray = [];

for (let file of dv.pages().file){
	for (let key of Object.keys(file.frontmatter)){
		
		// Check whether we've already captured this key in our array
		let i = null;
		i = uniqueKeyArray.findIndex((k) => k.fieldName === key);
		
		// If we haven't encountered this key before, push an
		// object with its key and intialized count to the array
		if (i === -1){
			i = uniqueKeyArray.push({fieldName: key, count: 0}) - 1;
		}
		
		// increase the running count for this unique key
		uniqueKeyArray[i].count++;
	}
}

// Create a table with "Unique Key" and "Key Count" headers from
// the array, sorting first alphabetically (ascending) then by
// count (descending). This puts keys with only capitalization
// differences together (at least in US English) so we can quickly
// see which version is more common.
dv.table(["Unique Key", "Key Count"], uniqueKeyArray
	.sort((a, b) =>
		a.fieldName.localeCompare(b.fieldName) || b.count - a.count)
	.map(k => [k.fieldName, k.count]));

As written, this will count every instance of a YAML field, even if it’s used multiple times in the same file.

I might eventually display the file names of anomalies in place of their “1” counts, but it’s pretty straightforward to search for a YAML field name once I know it exists, so I’m not rushing to do it. If you need that implementation but are new to coding and could use some help, let me know and maybe it will jump up my to-do list! My own coding skills are a teensy bit rusty, plus I started working with DataviewJS only yesterday, so if you have any suggestions or corrections I’d love to hear from you.

13 Likes

Well, I wanted to edit my reply above but am having problems editing it! Of course I realized only after I hit the “Reply” button that the following statement is just wrong:

As written, this will count every instance of a YAML field, even if it’s used multiple times in the same file

It seems to get very confused straight away if there are any indented keys in the frontmatter, omitting the indented key as well as both adjacent keys…I think? Clearly I have more testing to do. It will also only count one instance of a YAML field in a file, which is probably fine but contradicts what I said earlier. I would also like it to better handle nested keys, or other unusual YAML variations, but I don’t really know where to begin to learn about those–feel free to point me to any resources you know about funky YAML syntax that folks use in Obsidian!

I would really love it if the plugin exposed the keys themselves for regular queries, but I don’t know how many people suffer from my compulsion to tidy up YAML. I might have to teach myself to build a plugin just for auditing metadata in general!

If my editing functionality issue resolves, I will update my reply and remove this post to keep things uncluttered.

EDIT: of course it’s letting me edit this post and not the one above even though it hasn’t been that long (and didn’t let me edit even right after)…ugh.

3 Likes

Thanks so much for sharing this! @DeutscheGabanna and I were working on something similar, but for all DV keys/fields, not just ones in the frontmatter. Really neat to see an example for just frontmatter!

A couple things I learned from that thread:

  • For inline fields at least, dataview will essentially double-count any with capitalization or punctuation because it silently adds a normalized all-lower-case-dashes-in-place-of-spaces-ignore-other-punctuation version of the key to the page. Does it do that for frontmatter too?
  • I found a Map more intuitive than an array holding an object for the work you’re doing with uniqueKeyArray, but I haven’t experimented with making a dv.table of a map yet.
  • At the bottom of the code snippet in this post there’s code to do the displaying of filenames with keys that show up less than 3 times. I would probably change it to use localeCompare in my sorts now that I know about that thanks to your post!

Thanks again for sharing!

2 Likes

Ah thanks, I am absolutely going to check out your version!!!

  • I do the frontmatter-only version because I use inline keys for lazy description lists :smiley:…for now. I got the idea from other people, but I can’t find a link anywhere for the life of me.
  • I actually did several versions bouncing between different formats for holding the data, but my primary motivation was being rusty with JavaScript; I just needed a version that catered to the things I remember better :sweat_smile:. I would like to explore options that are more straightforward, so I REALLY appreciate you providing links and feedback!
  • localeCompare is pretty great :grin:

I want to iterate more on this soon, but I’m pretty pleased with what I have for my first dataviewjs block ever :slightly_smiling_face:.

2 Likes

I forgot to answer your question: for frontmatter, capitalization and punctuation differences are all counted separately (at least in my snippet)! I tested this with the following keys (all brand-new to my vault and placed together in one file’s YAML), and all of them were treated as unique and each was only counted once: catch:, Catch:, mind:, mind!:, head space:, head-space:, and headspace:.

1 Like

Hello, in my vault i have a folder called work here i create one note for each case i’m working. Inside those notes/cases I create a task list with dates like this - [ ] Do something [🗓️:: 2022-05-23].
Today i use this query to filter my tasks:

dv.taskList(dv.pages('"Notes/Work"')
.sort(p => p.file.name, 'asc')
.file.tasks
.where(t => !t.completed))        

My question is:

  1. Can i render task list where i filter only the tasks with [🗓️:: 2022-05-23] maker?
  2. Can i order this list by date of the marker [🗓️:: 2022-05-23] ?
  3. Can i render a list in this parameters: [ ] DATE: LINK_FOR_THE_NOTE
2 Likes

Dataview as of recently supports that emoji notation for certain task fields without the :: to be compatible with the Tasks plugin. If using that shorthand, the calendar/dates emoji turns into a field called due so you can write things like .where(t => t.due) or .sort(t => t.due, 'desc'). I don’t know whether it’ll work like that with your formatting - you’ll have to experiment!

I don’t understand your question 3 - could you elaborate a little more?

Now it renders like this:

image

And i want to render like this:

I see. I only know how to help with part of that. To get rid of the grouping into different lists, pass false as a second argument to the dv.taskList call. i.e. dv.taskList(..., false). You might be able to change what is displayed per-line by using a call to map(t => ...) at the end of your query after all the filtering and sorting. I imagine you could use that to put the file link in front of the task text for example. However since the due date is part of the task text I’m not sure how you would reorder that.

1 Like

First, thank you for sharing this and for all your other generous activity in the forum.

Because the Hotkey names are given in terms of Windows naming conventions, e.g. Alt not Opt, it can be confusing. This is particularly true for hotkeys that use the Mac Control key as it also listed as Ctrl. For example:

  • The default Hotkey for Open Settings is listed in this query as Ctrl+,. On a Mac that translates to Command+,
  • If I assign something to Control+, (Mac key names), it also shows up in the DV table as Ctrl+,

Here’s a clipping from the report after assigning Open Vault to “Control+,” as described above.

Both Open Settings and Open Vault appear to be assigned to “Ctrl+,” when, in fact, settings uses Command and Vault uses Control.

Would it be possible to modify the script to show the key names in Mac-speak (Command, Control, Option)?

1 Like

Hya,

sorry for the sudden ping on this, but it is almost exactly what I need.
A few short questions:

  1. Is it possible to exlude all notes within anyone of a set of folders when checking how many links some note has? For specific things I need a link threshold of 1, but I don’t want the 85-ish missing lecture files across 15 subjects to show up, nor some equally-yet-to-be-populated TOCs from elsewhere.
  2. Similar to above, could one exclude any file from being shown if the filename itself follows either a specified regex, or just a string-match against an array of blacklisted strings? Basically the same reason, only that I’d need to exclude certain sets of files in directories which also contain files I’d like to see.
  3. Does the snippet also take into account aliases within the frontmatter, or does it only match against exact filenames?
2 Likes

Question

What :: DataviewJS By Example Q181
fromURL :: patrick_ambrosso: DataviewJS Snippet Showcase Q181

Question :: How to get the number of orphan notes?

Answer :: See Code T06_A first.
WebUpdatedOn :: 2022-06-25
KeyClasses :: DataviewJS
toURL :: Solutions

Test06: Get the number of orphan notes(Tagged: Habit )

Inline DataviewJS Queries

ONLY for Inline Queries

T06_A_the number of orphan notes: $=dv.pages("#Habit").where((page)=>page.file.inlinks.length===0&&page.file.outlinks.length===0).file.name.length

  • Here is the output(non-HTML).
5
The following also can be executed within a DataviewJS block
  • dv.span() or dv.list() may be omitted in Inline DataviewJS Queries.

T06_B_the number of orphan notes: $=dv.span(dv.pages("#Habit").where((page)=>page.file.inlinks.length===0&&page.file.outlinks.length===0).file.name.length)

  • Here is the output(non-HTML).
5
DataviewJS block

T06_C_the number of orphan notes:

dv.span(
    dv
        .pages("#Habit")
        .where(
            (page) =>
                page.file.inlinks.length === 0 &&
                page.file.outlinks.length === 0
        ).file.name.length
);
  • Here is the output(non-HTML).
5
1 Like

Example of progress visualization via background color.

Problem: I wanted to visualize project progress, but printing just test looks boring and HTML progress element is actually an input which looks redundant. The idea is to use background color under project name, so it doesn’t take extra space. I followed the prototype you can check on StackOverflow.

DataviewJS:

// project icon, status etc comes from note frontmatter
// you may different props
const projects = dv.pages('"Backlog" and #project').sort(project => project.icon, 'desc');
for (let project of projects) {
    const total = project.file.tasks.length;
    const completed = project.file.tasks.filter((task) => task.completed).length;

    const rootEl = await dv.el('div', '', { cls: 'x-project-status' });
    const progressEl = rootEl.createEl('div', { cls: 'x-progress', attr: { 'data-label': project.file.name } });
    progressEl.createEl("a", { cls: 'x-percentage-fill', attr: { style: 'width:' + (completed / total * 100) + "%;" } });
    progressEl.createEl("a", { text: '↗', cls: 'x-link', attr: {
        href: project.file.link.path,
        'data-href': project.file.link.path,
        'aria-label': project.file.link.path,
        'aria-label-position': 'top',
        target: '_blank',
        rel: 'noopener'
    } });
    progressEl.createEl("span", { text: completed + ' / ' + total, cls: 'x-stat' } );
    rootEl.createEl("span", { text: project.icon + ' ' + project.status, cls: 'x-metadata' } );
}

CSS:

.x-project-status {
    display: flex;
    flex-direction: row;
    align-items: center;
}
.x-project-status>.x-progress {
    height: 2em;
    width: 40em;
    background-color: #f6f8fa;
    position: relative;
}
.x-project-status>.x-progress:before {
    content: attr(data-label);
    position: absolute;
    text-align: left;
    top: 5px;
    left: 5px;
    right: 0;
}
.x-project-status>.x-progress>.x-percentage-fill {
    background-color: #dafbe1;
    display: inline-block;
    height: 100%;
}
.x-project-status>.x-progress>.x-link {
    position: absolute;
    text-align: right;
    top: 5px;
    right: 5px;
    text-decoration: none;
    color: #0969da;
}
.x-project-status>.x-progress>.x-stat {
    position: absolute;
    text-align: right;
    top: 5px;
    right: 2em;
    color: #57606a;
    font-size: 0.8em;
}
.x-metadata {
    padding-left: 10px;
    font-size: 0.9em;
}

Result:

9 Likes

I know a teeny tiny bit of dvjs. I have a use case for it that is probably very easy. I’d like to count the number of times a set of words or phrases show up in my “wellness” field. I want to map how many times I’ve done certain things – or logged them at any rate.

field example:
in my daily notes, in my “Bujo” folder, each day has this kind of information.
Wellness: drank water, painkillers, music.

what I’d like is to count how many times I’ve used “water,” “painkillers,” “music” etc.
my daily note title template is 2022-07-06 – Wednesday for example.

Can this be done easily? If so, how?

Thank you.

I want to create a simple chart from my Daily notes with Dataview and/or DataviewJS.
Can you help me with some sample code, please?
Thank you! :smile:

1 Like

Hi snowbiker100, to make a chart you’ll almost certainly want some additional plugin that makes charts. I know there are several in the community directory. One I have used with dataview fields is obsidian-tracker, which has lots of code examples in an examples dorectory on github, including ones that use dataview fields. Hopefully other folks who have used other chart/graph/data-visualizarion plugins can chime in with advice also!

Do you mean “Obsidian charts” plugin? I’m not directly familiar but this documentation page shows a dataviewjs example. It looks like other pages on that documentation site have an example of a bar chart with multiple bars per day.
A thought independent of the programming: if you put everything on your example diagram on the same chart it is going to be really hard to see the “Fitness” and “Writing” bars because the numbers for “Nutrition” are so big!

Good luck!