How to use dataview to show wikilinks from property array

What I’m trying to do

I am making a lots of skills for a game that all have mentors and students. If skill A is mentor to skill B, then skill B is a student to skill A.
It is possible to be a Mentor and Student to the same skill at the same time.

The Mentors and Students are put as a list of properties in each skill file.

What I want to do is create two dataview tables in each file. One showing all the students to the current file and one with the mentors. The tables should also be able to be copy and pasted to all the files.

Things I have tried

I have one solution but it requires all mentors and students to be filled. This makes double work cause if one is a mentor then the student relationship is already there and should not need to be added. Plus if I make a new file then I need to edit all other related files.

Here are 4 files as an example:

Axe

tags: #skill
mentor:

  • “[[Close quarters combat]]”
  • “[[Club]]”
  • “[[Staff]]”

student:

  • “[[Club]]”

Close quarters combat

tags: #skill
mentor:
student:

  • “[[Axe]]”
  • “[[Club]]”
  • “[[Staff]]”

Club

tags: #skill
mentor:

  • “[[Axe]]”
  • “[[Close quarters combat]]”
  • “[[Staff]]”

student:

  • “[[Axe]]”

Staff

tags: #skill
mentor:

  • “[[Close quarters combat]]”

student:

  • “[[Axe]]”
  • “[[Club]]”

And then all of the files have the following dataviews that works fine.

Mentor to:

TABLE 
FROM #Skill 
WHERE contains(Mentor, [[]])

Student to:

TABLE
FROM #Skill 
WHERE contains(Student, [[]])

Lets say I make a new file called sword

Sword

tags: #skill
mentor:

  • “[[Close quarters combat]]”
  • “[[Staff]]”

student:


Now the dataviews in the sword file will be empty, but Close quarters combat and Staff will be updated. Sword does not read it’s own file.
After looking around this one gave me some insight

In the other files I just use WHERE to see if [[Sword]] exists. But from Swords perspective I would need to unpack an array of links from itself.

So far I have been unable to do this. How to go about this?
Table with:
Files containing [[XXX]] in Student.
All the files in the Mentor links from the XXX file.
No duplicates.

Table with:
Files containing [[YYY]] in Mentor.
All the files in the Student links from the YYY file.
No duplicates.

I do believe you need to simplify your structure, but I’m a little confused on the terms you’ve used with mentor and student. To me I wouldn’t list the students of a given mentor in the mentor file, since in my head the mentor is most likely not to change, but you’ll change students rather often.

So I’d most likely list who is the mentor in a student file. I’m not sure if this is what you’re thinking, or whether you’re thinking more of required skill to master another skill… So in the following I’ve used the following set of files:

  • Axe with mentor: Close quarters combat, Club, Staff
  • Close quarters combat with mentor: axe, club, staff
  • Club with mentor: axe, close quarters combat, staff
  • Staff with mentor: Close quarters combat
  • Sword with mentor: close quarters combat, staff

So here is one example with some variations on how the Axe could look like:

---
tags:
- skill
mentor:
- "[[Close quarters combat]]"
- "[[Club]]"
- "[[Staff]]"
---


## Students?

```dataview
LIST
FROM #skill 
WHERE contains(mentor, [[]])
```

## Mentors

### inline query: 
`= this.mentor `

### dataviewjs
`$= dv.list(dv.current().mentor) `

### dataview
```dataview
LIST WITHOUT ID aMentor 
FROM #skill
WHERE file = this.file
FLATTEN this.mentor as aMentor
```

Which with Minimal theme could look like:

For an actual solution I would strongly consider having these kind of queries in a javascript file, and use dv.view() to call that script. This would allow you to change that one script in the future if you wanted to include other information, or change the information provided and so on.

Thanks for taking the time to answer, I will look if that could work. Also great tip about making a script that is used everywhere so I can change the table everywhere form one place.

In my project I have over hundred skill files, so when I add a new file I want to make the new file related to the other ones without editing any old file. Hence why you can add ‘both directions’,.

I think to simplify what I am looking for that I can’t figure out, accessing properties from a link in a specific property.:

For example, let say I have file called Hunt with the following

Hunt

Student:

  • [[Traps]]
  • [[Wildlife]]

Summary: Find and catch animals
Spam:

  • [[Sword]]
  • [[Axe]]
  • [[CQC]]

I want a table that shows the students from Hunt and then their properties.

Dataview logic in hunt file

Name, Summary
Traps, Create traps
Wildlife, Animal knowledge

And not showing anything from Spam or some other link in the file.

Was able to do this.

TABLE WITHOUT ID Student.Name, Student.Summary
WHERE (file = this.file)
FLATTEN Student

Now I just need to figure out how to combine the old table with this one. But that is a question for later.

I was able to solve it but it required some javascript, shown below.
With this I could call on
```dataviewjs
customJS.MacroGuide.skillInfo(dv);
```
in my file inside of obsidian.
And then this would create a table filled with info I put in the properties in the same file and other files.

javascript was easy when I figure out how to properly use the dv.
In my case I had to convert most things to strings to compare them.
But for testing you could use dv.paragraph() to see what was compared in printed text, just remember to add \ before symbols else details might be lost.

skillInfo(dv) {
    let index = 0;
    const mentorContent = dv.pages("#Skill").where(X => this.isMentor(dv, X))
      .sort(b => b.file.link)
      .map(b => [++index, b.file.link, b.Name, b.Core, b.Rarity, b.Bonus, b.Summary]);
    if (mentorContent.length != 0) {
      const mentorTable = dv.markdownTable(["", "Link", "[[Mentor]]", "Core", "Rarity", "Bonus", "Summary"], mentorContent);
      dv.paragraph("This skill is mentor to:");
      dv.paragraph(mentorTable);
    }

    index = 0;
    const studentContent = dv.pages("#Skill").where(X => this.isStudent(dv, X))
      .sort(b => b.file.link)
      .map(b => [++index, b.file.link, b.Name, b.Core, b.Rarity, b.Bonus, b.Summary]);
    if (studentContent.length != 0) {
      const studentTable = dv.markdownTable(["", "Link", "[[Student]]", "Core", "Rarity", "Bonus", "Summary"], studentContent);
      dv.paragraph("This skill is student to:");
      dv.paragraph(studentTable);
    }
  }
isMentor(dv, X) {
    if (X.Mentor) {
      for (let j = 0; j < X.Mentor.length; j++) {
        let xMentor = X.Mentor[j].toString();
        let fileLink = dv.current().file.link.toString();
        if (xMentor === fileLink) {
          return true;
        }
      }
    }
    if (dv.current().Student) {
      for (let i = 0; i < dv.current().Student.length; i++) {
        let fileStudent = dv.current().Student[i].toString();
        let xLink = X.file.link.toString();
        if (fileStudent === xLink) {
          return true;
        }
      }
    }
    return false;
  }
isStudent(dv, X) {
    if (X.Student) {
      for (let j = 0; j < X.Student.length; j++) {
        let xStudent = X.Student[j].toString();
        let fileLink = dv.current().file.link.toString();
        if (xStudent === fileLink) {
          return true;
        }
      }
    }
    if (dv.current().Mentor) {
      for (let i = 0; i < dv.current().Mentor.length; i++) {
        let fileMentor = dv.current().Mentor[i].toString();
        let xLink = X.file.link.toString();
        if (fileMentor === xLink) {
          return true;
        }
      }
    }
    return false;
  }