Dataviewjs - find tasks that contain a link in their metadata

Things I have tried

dv.taskList(
	dv.pages("[[person]]").file.tasks  
	    .where(t => t.waitingfor)
	    .where(t => t.waitingfor === "[[person]]")
);

Also other permutations of similar ideas. For example, I also tried with include as:
.where(t => t.waitingfor.include("[[person]]")

which throws an error.

What I’m trying to do

I want to find all my tasks that contain the waitingfor metadata that are assigned to a specific person. For example the task:

- [ ] this is [waitingfor:: [[person|nickname]]]

The following dataview query works magnificently

TASK
FROM [[person]]
WHERE !completed
  AND contains(waitingfor, [[person]])

but I want to convert the above query to dataviewjs.

Today is not my day, I just spent a few hours trying to convert your script into javascript, and ran into all kinds of troubles, because the simple equality check done in DQL queries are not easily replicated in dataviewjs, I thought. But finally I found a nicer solution, so let’s go.

Re-use your DQL query

You’re free to re-use your DQL-query within dataviewjs, and then it would look something like this:

```dataviewjs
const tasks = await dv.tryQuery(`
TASK 
FROM [[]]
WHERE !completed
  AND contains(wait, [[]])
`)

dv.taskList(tasks.values, false)
```

You’re free to handle the return values before presenting them in either case, or if you just want to present it directly, you could skip the intermediate storage in tasks, and do something like dv.taskList(await dv.tryQuery().values, false). But then again, then what’s the point of doing it within dataviewjs?

Rewrite the query into a daisy chain

The trick, which I used way too long to find, to recreate the query is that we got access to the DQL functions through dv.func. The query can then be rewritten as follows:

testFile:: [[]]

```dataviewjs
const testLink = dv.current().testFile
// await dv.page("f52363 DVJS wait").file.link

const tasks = await dv.pages(
    "[[f52363 DVJS wait]]")
    .file.tasks
    .where(t => !t.completed)
    .where(t => {
      return dv.func.contains(t.wait, testLink)
    })

dv.taskList(tasks, false)
```

My test setup used the f52363 DVJS wait to test the links against, and so on. In the script I also have commented out, one way to get another file as the testLink (for example “Person”). I would however rather re-define it outside of the script, like testFile:: [[Person]]

Warning: If you define the file you want to test against inside the script, then be warned that if you change the name of that file elsewhere within Obsidian, it’ll not be updated. If however, you define an inline field outside of the script, and pick it up, it’ll be renamed as normal. (Please ask if this was confusing!)

My complete test-page

Under here is my complete test-setup, which is stored in a note name “f52363 DVJS wait”. It also includes my longer version which didn’t use dv.func.contains(), and a TABLE query to display some of the issues related to object equality in DQL queries, which are not present if you daisy chain stuff and do the filter variant.

Not sure if it’s useful, or not, but here is the code I’ve been tinkering with for a few hours:

 ---
Tags: f52363
---
questionUrl:: http://forum.obsidian.md/t//52363

## Definition
- [ ] original   [wait:: [[f52363 DVJS wait]]]
- [ ] full path  [wait:: [[ForumStuff/f52363/f52363 DVJS wait]] ]
- [ ] alias      [wait:: [[f52363 DVJS wait|DVJS link]] ]
- [ ] org+sand   [wait:: [[f52363 DVJS wait]], [[Sandbox]] ]
 - Not a task, nor any links
 - [ ] stringy     [wait:: "Sandbox"]

## Re-use query
```dataviewjs
const tasks = await dv.tryQuery(`
TASK 
FROM [[]]
WHERE !completed
  AND contains(wait, [[]])
`)

dv.taskList(tasks.values, false)
```

## Equality in DQL
```dataview
TABLE WITHOUT ID
  substring(task.text, 0, 9) as text,
  task.wait,
  task.wait = [[]] as object_equality,
  contains(task.wait, [[]]) as contains
FLATTEN file.tasks as task
WHERE file.name = this.file.name
```

## Equality in dvjs
testFile:: [[]]
NotestFile:: [[Sandbox]]

```dataviewjs
const testLink = dv.current().testFile
// await dv.page("f52363 DVJS wait").file.link

console.log("testLink", testLink)

const tasks = await dv.pages(
    "[[f52363 DVJS wait]]")
    .file.tasks
    .where(t => !t.completed)
    .filter(t => {
      const justText = t.text.slice(0, 9)

	  // Check if single value link ...
      if (t.wait?.path != undefined) {
        return t.wait.path == testLink.path
      } else if (t.wait[0]?.path != undefined ) {
        // ... or array
        for (let link of t.wait) {
           if (link.path == testLink.path)
             return true
        }
        // Looped array, and none found
        return false
      } else {
        // No single link or array of links
        console.log("Error", t.wait)
        return false;
      }
    })

dv.taskList(tasks, false)
```

## DVJS with func.contains
```dataviewjs
const testLink = dv.current().testFile
// await dv.page("f52363 DVJS wait").file.link

console.log("testLink", testLink)

const tasks = await dv.pages(
    "[[f52363 DVJS wait]]")
    .file.tasks
    .where( t => !t.completed )
    .where( t => dv.func.contains(t.wait, testLink) )

dv.taskList(tasks, false)
```

So there you have it, a fully rewritten DQL query into dataviewjs. Hope this helps you on your quest forward, even if my test-setup wasn’t completely equal to your query. I reckon you can make the final changes to get it working in your case, rather easily.

2 Likes

Well, that’s a great way to start my day :slight_smile:
I can’t thank you enough! Thanks a lot @holroy !

I’m no expert in js and I’ve spent so much time trying to do something.

Cheers!

1 Like

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