Creating a table of notes grouped by other notes

Summary

I would like to create a dataview query which uses category notes as the group headers and lists all linked subcategories within the group contents, and which does this dynamically so I don’t need to create separate queries for each new category added.

Context Explanation

I have notes in my vault organized by primary and secondary categories (e.g., categories and subcategories). Each secondary category is linked to a primary category, and one primary category would have multiple subcategories. All of these are notes, and then individual notes within my vault link to the relevant primary and secondary categories.

For Example:

Primary category note named 01-Animals
Secondary category notes 02-Lions, 02-Tigers, 02-Bears – all linked to 01-Animals

Then an atomic note would include the following content (not front matter – actual note content):

(Note title, such as “Study of interesting pack behaviors of lions”)
Primary Category: [[01-Animals]]
Secondary Category: [[02-Lions]]
(Note contents… etc…)

There are obviously multiple primary categories. The secondary categories are added organically as a new subtopic area comes up.

Finally, since I’m using templates for each note type, the primary and secondary category notes can be easily identified because they use the tags #PrimaryCategory and #SecondaryCategory, respectively

My Question

Is there a way to use dataview, perhaps specifically the dataviewjs ‘group’ capability, to dynamically generate a table/list/whatever which uses the Primary Category notes as group headers then lists all associated Secondary Category notes within that group?

I’m thinking something along the concept of the output shown here. Except instead of the subject being the group header, it’s the primary category note. Something like this:

01-Animals

01-Plants

Is something like this at all possible? How might I go about it?

My initial thought for pseudocode logic (and this is definitely not dataview or dataviewjs format-ready) would be along the lines of:

for (let group of dv.pages("#PrimaryCategory").groupBy(p => p.file.link)) {
    dv.header(3, group.key);
# Pseudocode starts here!!!
    dv.table(
        from [[group.key]] and "#SecondaryCategory"
    )
}

Thoughts? Suggestions? Thanks in advance!

Hi. I only know to work with DQL queries, I don’t have knowledge in JS.
With this query you can group all wanted notes in one table:

```dataview
TABLE rows.file.link as Secondary
FROM #SecondaryCategory
FLATTEN file.outlinks AS Primary
GROUP BY Primary
SORT Primary ASC
```

This works considering that the only outlink from #SecondaryCategory notes are #PrimaryCategory notes.

I understand that in your case can be useful not one unique table but multiple tables by primary category. With the same condition (the only outlink from #SecondaryCategory notes are #PrimaryCategory notes) I tried some JS…

A table (with links to secondary category note from other notes - you can remove or replace this field):

```dataviewjs
for (let group of dv.pages("#SecondaryCategory").groupBy(p => p.file.outlinks.toString())) {
    dv.header(3, group.key);
    dv.table(["Name", "Links From"],
        group.rows
            .sort(k => k.file.link, 'asc')
            .map(k => [k.file.link, k.file.inlinks]))
}
```

A list:

```dataviewjs
for (let group of dv.pages("#SecondaryCategory").groupBy(p => p.file.outlinks.toString())) {
    dv.header(3, group.key);
    dv.list(
        group.rows
            .sort(k => k.file.link, 'asc')
				.file.link)
}
```

These are queries created based in one example in plugin documentation and with “tentative-error” method. Maybe not the best solution.

This is helpful. Not quite there, but it’s helpful. Thanks!

Unfortunately we can’t assume that the only link from a secondary category note is to a single primary category note. I flipped around some of your code and ended up with this:

```dataviewjs
for (let group of dv.pages("#PrimaryCategory").groupBy(p => p.file.link)) {
	dv.header(3, group.key);
	dv.table([""],
		group.rows
			.sort(k => file.link, 'asc')
			.map(k => [k.file.inlinks]))
}

Result:

That gets me all the primaries as headers, but it’s returning EVERY note linked to the primary, not just the secondaries. Any idea how to filter the rows to just show secondaries? Either by looking at the k.file.inlinks bit to see if that file is tagged #SecondaryCategory or even just by doing a text filter of the inlinks for note titles/file names starting 02-*?

Well, your query is similar, but inverted - the issue is the same: how to filter the results? (in my query it’s necessary to filter the “outlinks”; in your the “inlinks”).

This goes beyond my almost null knowledge in JS. :confused:

In DQL it’s easy:

## by outlinks

```dataview
TABLE sort(rows.file.link) as Secondary
FROM #SecondaryCategory
FLATTEN file.outlinks AS Primary
WHERE contains(Primary.file.tags, "#PrimaryCategory")
GROUP BY Primary
SORT Primary ASC
```

## by inlinks

```dataview
TABLE sort(rows.Secondary) AS Secondary
FROM #PrimaryCategory
FLATTEN file.inlinks AS Secondary
WHERE contains(Secondary.file.tags, "#SecondaryCategory")
GROUP BY file.link
```

But in dataviewjs I really don’t know how to solve two questions:

1 - how to place .where between dv.pages and .groupBy (because the filter need to be at file level, not page level);

2 - what is the equivalent to dql contains in js (includes()?).

But… considering your last comment about k.file.inlinks I tried a filter function directly on it.

```dataviewjs
for (let group of dv.pages("#PrimaryCategory").groupBy(p => p.file.link)) {
	dv.header(3, group.key);
	dv.table([""],
		group.rows
			.sort(k => file.link, 'asc')
			.map(k => [k.file.inlinks.filter(l => dv.page(l.path).file.tags.includes("#SecondaryCategory"))]))
}
```

It seems to work, but I’m not very confident and secure…

Definitively this (js) is not my ground… :roll_eyes:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.