When I meet with the same person multiple times, I feel bad when I don’t remember “the little things” about them. I want to have an easy way to extract personal details (e.g. college attended, favorite foods, kids’ names, partner name, etc…) from meeting notes into a Person page for individuals with whom I speak on a regular basis. This will also help me to thoughtful things for them over time that are personal to them.
Solution:
I include the snippet below in the Personal Notes section (header 2) of my Person template:
All of my Person notes in my People folder are titled with just the person’s name. So, the above snippet allows me to type the person’s name (caps sensitive) as inline metadata in any note, extract those details, and aggregate that text in the hub note for that Person. The line gets printed in the Person note as the actual text rather than just the link to the file.
E.g. if I write the below in any note, what will get printed in the Zack Ellis page will be “kids are Pinky and The Brain”
title: DQL10_pull_person_note_metadata_into_meeting_note_by_using_file.outlinks =>1.To break up a list `this.file.outlinks` into each individual element `P` 1.1 `this.file.outlinks`: a list of links 1.2 `P`: a link 2.To filter by `P.file.name` 3.To filter by `P.tags` 4.To display the result as a table
collapse: close
icon:
color:
```dataview
TABLE WITHOUT ID
P AS "person",
P.children AS "children",
P.hobbies AS "hobbies"
FROM "100_Project/02_dataview/Q23_meeting/Q23_test_data/Meeting/20221217_meeting.md"
FLATTEN this.file.outlinks AS P
WHERE !contains(P.file.name, "Template")
WHERE contains(P.tags, "person")
```
1.To break up a list this.file.lists into each individual element L 1.1 this.file.lists: a list of links 1.2 L: a link
2.To define a field variable F_subpath 3.To define a field variable F_type 4.To filter by F_type 5.To filter by F_subpath 6.To FLATTEN L.outlinks AS P 7.To filter by P.file.name 8.To filter by P.tags 9.To display the result as a table
title: DQL20_pull_person_note_metadata_into_meeting_note_by_using_L.outlinks =>1.To break up a list `this.file.lists` into each individual element `L` 1.1 `this.file.lists`: a list of links 1.2 `L`: a link 2.To define a field variable `F_subpath` 3.To define a field variable `F_type` 4.To filter by `F_type` 5.To filter by `F_subpath` 6.To FLATTEN L.outlinks AS P 7.To filter by `P.file.name` 8.To filter by `P.tags` 9.To display the result as a table
collapse: close
icon:
color:
```dataview
TABLE WITHOUT ID
P AS "person",
P.children AS "children",
P.hobbies AS "hobbies"
FROM "100_Project/02_dataview/Q23_meeting/Q23_test_data/Meeting/20221217_meeting.md"
FLATTEN this.file.lists AS L
FLATTEN meta(L.header).subpath AS F_subpath
FLATTEN meta(L.header).type AS F_type
WHERE F_type = "header"
WHERE F_subpath = "Attendees" OR F_subpath = "Host"
FLATTEN L.outlinks AS P
WHERE !contains(P.file.name, "Template")
WHERE contains(P.tags, "person")
```
I love this, thanks! However, I’m getting a weird error now, though a bit ago I had it working perfectly. Any chance you know what’s going wrong here? See below for the error i’m getting:
I recreated this scenario in a new vault and it worked. Nothing jumps out at me as to why there is a problem. ¯\(ツ)/¯
My advice is:
Restart Obsidian and see if the query works. I’ve noticed that sometimes the Dataview plugin will “glitch out” and only a restart “fixes it”.
If it is still broken, try to isolate the issue…
a. Recreate this scenario in a new vault
b. Add one meeting at a time until the problem occurs.
c. Compare the bad meeting with a good meeting.
d. You may need to replace values in the bad meeting with those from the good one to identify bad data. Even the frontmatter.
Let me know how you get on. I suspect it is a “bad meeting” file.
Hey @Gahrae, great script. I was not aware how “mighty” Dataview could be. I have implemented this into my template for meeting notes.
I just stumbled across a similar problem like @Dutchnesss
Evaluation Error: TypeError: Cannot read properties of null (reading '1')
at eval (eval at <anonymous> (plugin:dataview), <anonymous>:25:72)
at Array.map (<anonymous>)
at Proxy.map (plugin:dataview:8038:39)
at getLinkedPeople (eval at <anonymous> (plugin:dataview), <anonymous>:25:27)
at displayAttendeeFacts (eval at <anonymous> (plugin:dataview), <anonymous>:6:15)
at eval (eval at <anonymous> (plugin:dataview), <anonymous>:3:1)
at DataviewInlineApi.eval (plugin:dataview:18404:16)
at evalInContext (plugin:dataview:18405:7)
at asyncEvalInContext (plugin:dataview:18415:32)
at DataviewJSRenderer.render (plugin:dataview:18436:19)
I could trace this back to an image that I embedded - ![[Pasted image 20230808090346.png]] - into my notes. When I remove it the table comes back.
Any idea how to exclude images during the eval of the document and finding people?
let attendees = outlinks.map((link) => link.path.match(/.*\/(.*)\.md/)[1])
with
let attendees = outlinks
.filter((link) => link.path.endsWith('.md'))
.map((link) => link.path.match(/.*\/(.*)\.md/)[1])
Explanation: The match function tried to extract out part of the file name. This would fail when the file name did not end with ‘.md’, that is, it was not a link to a markdown file. The solution is to first filter for only those links which are to markdown files.
Pro-tip: It can be helpful to open the Chrome developer console and use debugging statements to identify and resolve javascript issues. For example, add console.log(outlinks) to see what the contents are.
Thanks a lot! Very helpful with the details and explanations. I’m new to Python and JS - however coming from PHP, Java, C++, Obj C and SWIFT - I need to learn a new “dialect”
I found the Codeblock Reference for DataviewJS - this helps a lot. I’m currently trying to understand:
Obviously this is the way to sort the Table, I have a column “org” - and I would like to use this to sort the table. So consulting the Codeblock Reference and your code, my column are in “let factColumns = facts.map(fact => page[fact])” so I thought:
The code fragment sort(page => page.file) is actually broken. I’ve viewed it with the developer console and can see that the property doesn’t exist.
Attached is an image that shows using the developer console to examine the data. This image shows the correct way to sort by the person’s name. This happens to be in the property named path.
However, you wanted to sort by an attribute, that is ‘org’.
A messy way to do this, is to use the index of the attribute: .sort(page=> page[1], "asc"))
A cleaner way is to obtain this value directly from the associated markdown file given it’s name. Below is an updated code fragment to sort by a provided field and in a certain sort order (i.e. ‘asc’ or ‘desc’).
let facts = ["org"]
displayAttendeeFacts(facts, "desc", "org")
function displayAttendeeFacts(facts, sortOrder = "asc", sortField = "path") {
let people = getLinkedPeople()
let tableColumns = ["person"].concat(facts)
let tableDataFunction = (page) => {
let personColumn = [dv.fileLink(page.file.name)]
let factColumns = facts.map(fact => page[fact])
return personColumn.concat(factColumns)
}
if (people.length > 0) {
dv.table(tableColumns,
people
.map(tableDataFunction)
.sort(item => dv.page(item[0])[sortField], sortOrder))
} else {
dv.paragraph("No people.")
}
}
Overall, this code could be reworked to be cleaner, but it’ll get the result you are after.
Thanks a lot. I got it solved with the Index. I needed to figure out how “arrays” are working in JS. Well still not sure if it’s an array or struct, but you never know in some languages you can use an index, other use a name…
Your code sample is much better as it allows more flexibility in case for reuse!
Thanks again! Much more help than expected. I did some “stalking” and found your ko-fi page and used it! Great help! - I will take a deeper dive into debugging JS in the next couple of days when I have time.
Adding a quick update here that I modified my code snipped that I include in the Person Note links back automatically to the Meeting Note where I added personal details: