Dataview : List of file group by nested tag

Hello,

For each of my projects, I have a folder containing the list of tasks to be carried out.
These tasks contain metadata:
task:

  • project:
  • status: " #status "
  • priority: " #priority "
  • size: "#size "
  • type:

I also have a page containing the “summary” of my project in which I want to list all these tasks in a table.

Currently with this querry I can get the task list :

TABLE
filter(task.status, (x) => x) as Status,
filter(task.priority, (x) => x) as Priority, 
filter(task.size, (x) => x) as Size
FROM "002-Project" 
WHERE contains(task.project, this.file.name)

There are still the extra dots I’d like to remove but it’s not the priority and I don’t even know if it would be possible

Anyway I haven’t found a more elegant way to display my data, in fact without the filters this is what I get:

Now I would like to be able to group my tasks by status (done, in-progress, …) or even, if possible, sort them by priority (urgent, high, medium, low) but I don’t see how to do it. Do you have any ideas?

Edit :

For the dot problem and to make my table more readable, I have modified my code as follows :

TABLE
string(map(filter(task.status, (x) => x), (t) => split(t, "/")[1])) 
as Status,
string(map(filter(task.priority, (x) => x), (t) => split(t, "/")[1]))  
as Priority, 
string(map(filter(task.size, (x) => x), (t) => split(t, "/")[1]))  
as Size
FROM "002-Project" 
WHERE contains(task.project, this.file.name)

Hmm… I think there might be something wrong with your base data. Are they defined as tasks, or what are they defined as?

When you get multiple status lines like you do, there is most likely more than one task in each file. How does your task definitions look like? Does every task have the status, priority and size defined?

Well, this is how my tasks are defined :

When I say “tasks” I don’t mean tasks in the sense of checkboxes, but pages containing what needs to be done, such as a feature, a bug fix etc…

“When you get multiple status lines like you do, there is most likely more than one task in each file”

=>

For one row in my table, I think the different points are relative to the other attributes in “task” like task.status, task.priority etc… So when I do a query to retrieve only task.status, I think the query will evaluate each of the attributes contained in task and return something like [null, null, priority/low, null, null] (in the case where I am looking to retrieve the priority of a page).

Currently, I haven’t managed to make a real group by so I decided to make several queries with a WHERE allowing me to retrieve only the pages with the “in-progress” tag then the one with the “done” tag etc… It’s not very clean but it’s the only thing I managed to produce.
Now I’m trying to create a custom order but it doesn’t seem to work…

TABLE
string(map(filter(task.priority, (x) => x), (t) => split(t, "/")[1]))  
as "Priority", 
string(map(filter(task.size, (x) => x), (t) => split(t, "/")[1]))  
as "Size",
string(filter(date.started, (x) => x)) as "Started",
string(filter(date.deadline, (x) => x)) as "Deadline"
FROM "002-Project" 
WHERE contains(task.project, this.file.name)
WHERE contains(task.status, "#status/in-progress")
SORT choice(task.priority = "low", 1,
choice(task.priority = "medium", 2,
choice(task.priority = "high", 3,
choice(task.priority = "urgent", 4, "other")))) DESC

It turns out it’s your markup which is slightly wrong, because when you use - to prefix them, you’re saying that you want to accumulate a list of values for the key, in your case the task. So you do get the list you refer to, and not the actual object values you’re looking for.

Try the following markup:

---
date:
- created: 2023-01-07

task:
  project: Test-project
  status: "#status/backlog"
  priority: "#priority"
  size: "#size"
  type:
---

And you’ll see that you can use task.status in a simpler and more direct way.

Bonus tip on requests: If you surround your code blocks with ```` before and after the code blocks you want to present, you’ll get a better output, showing the inner code blocks with proper code fences.

Thank you very much! It’s so much easier that way! The only thing left is the problem of sorting the rows with a custom order that I can’t solve even with the modification…

Yes, I think it wasn’t working because I was putting the language name “dataview” after the “```”.

I’m not quite seeing how you aim to sort, but could something like the following help you on the way:

```dataview
...
FLATTEN choice(task.priority = "low", 1,
         choice(task.priority = "medium", 2,
          choice(task.priority = "high", 3,
           choice(task.priority = "urgent", 4, 9999)))) as priNum
WHERE ...
SORT priNum DESC
```

Well, I must be missing something, this isn’t working either! I’ll look at it tomorrow, thanks for your help and your time!

An alternative way to map the values could be:

FLATTEN object(
  "low", 1,
  "medium", 2,
  "high", 3,
  "urgent", 4)[task.priority] as priNum

This also produce the values 1 through 4 into priNum, or if you want a default value if nothing matches:

FLATTEN default(object(
  "low", 1,
  "medium", 2,
  "high", 3,
  "urgent", 4)[task.priority],
  9999) as priNum

I reread your original query, and there was a vital little bit on splitting the task priority I missed, so my previous three FLATTEN variants was all missing since they expected low and not #priority/low.

So here is the object variant with default and proper handling:

```dataview
...
FLATTEN split(task.priority, "/")[1] as priText
FLATTEN default(object(
  "low", 1,
  "medium", 2,
  "high", 3,
  "urgent", 4)[priText],
  9999) as priNum
WHERE ...
SORT priNum DESC
```

Here task.priority = "#priority/low" will then go to priText = "low", which finally will map into the priNum = 1, which is then used for sorting. Hope that works for you when you insert it into the full query of yours, it does work for me at least in a mockup query.

I think I must have something different from you because it doesn’t work unfortunately…
At the moment, after correcting the problems you have pointed out, here is the current state of my work:

Metadata of the pages I am trying to retrieve :

date:
 created: 2023-01-08
 started: 
 completed: 2023-01-07
 deadline: 

task:
 project: Project_Test
 status: " #status/done"
 priority: " #priority/low"
 size: " #size"
 type: 

The query :

TABLE
task.priority as "Priority",
task.size as "Size",
date.completed as "Completed"
FROM "002-Project" 
WHERE contains(task.project, this.file.name)
WHERE contains(task.status, "#status/done")

Response :

So based on that, I’ve added the code below to sort my table :

TABLE
task.priority as "Priority",
task.size as "Size",
date.completed as "Completed"
FROM "002-Project" 
FLATTEN default(object(
  "#priority/low", 1,
  "#priority/medium", 2,
  "#priority/high", 3,
  "#priority/urgent", 4)[task.priority],
  9999) as priNum
WHERE contains(task.project, this.file.name)
WHERE contains(task.status, "#status/done")
SORT priNum DESC

Response :

See my last reply, you forgot the FLATTEN split line and the change to use priText. It could be a better solution, since you set the priority with a space in front.

Alternatively, you could try to change the object to use alternatives with the space, like " #priority/low", and so on.

I didn’t succeed with this other solution either… But in the meantime I discovered that you could use javascript with dataview and everything became easier haha!

So here is my working solution, thanks for your help !

function getFormattedTitle(string) {
	const splitedString = string.split("/")[1]
	return splitedString.charAt(0).toUpperCase() + splitedString.slice(1);
}

function getTrimmedValuesFromObject(object) {
	return Object.values(object).map(x => x.trim())
}

function getPages(statusTable) {
    return dv.pages('"002-Project"').where(page => {
		return page.task.project === "Project_Test";
	}).where(groupedPage => {
		return groupedPage.task.status.trim() === statusTable
	})
}

const statusObject = dv.pages('"998-Resources/enum/_status"').values[0].status
const statusValues = getTrimmedValuesFromObject(statusObject)
const priorityObject = dv.pages('"998-Resources/enum/_priority"').values[0].priority
const priorityValues = getTrimmedValuesFromObject(priorityObject)

statusValues.forEach(statusTable => {
	dv.header(2, getFormattedTitle(statusTable))
	const pages = getPages(statusTable)

    const printTable = pages.map(row => {
		const fileLink = row.file.link;
		const priority = row.task.priority;
        const priorityValue = priorityValues.indexOf(row.task.priority.trim())
		const size = row.task.size;
		const completed = row.date.completed;
		return [fileLink, priority, size, completed, priorityValue];
	}).sort(x => x[4], "desc")
    .map(x => x.slice(0, 4))

	dv.table(["File", "Priority", "Size", "Completed"], printTable)
})

It doesn’t work for you with the following query?

```dataview
TABLE
task.priority as "Priority",
task.size as "Size",
date.completed as "Completed"
FROM "002-Project" 
FLATTEN split(task.priority, "/")[1] as priText
FLATTEN default(object(
  "low", 1,
  "medium", 2,
  "high", 3,
  "urgent", 4)[priText],
  9999) as priNum
WHERE contains(task.project, this.file.name)
WHERE contains(task.status, "#status/done")
SORT priNum DESC
```

That is kind of strange, I reckon there are some differences in the way we’ve setup the data. (I must not have understood it correctly how you’ve setup yours)

Anyways, I’m happy you found a solution to your request.