Last time, I described how I started using Obsidian to keep track of my contacts. I have been fine-tuning the setup significantly to get it to work even better for me. To turn it into more of a database that’s queryable, I installed the Dataview plugin.

You can define fields within notes both in the markdown note itself (inline fields), or the yaml frontmatter. Inline fields use the syntax key:: value if you want the field name displayed, or (key:: value) if you want the field name hidden. With some caveats, most information in the frontmatter is indexed by default. I won’t go into too many of the specifics of Dataview, but the documentation is fairly good if you have questions.

With Dataview, my template has changed significantly. My frontmatter now contains social links in addition to contact tags:

created: ["{{date}} {{time}}"]
  - name: "🦣 mastodon"
    link: ""
  - name: "🐦 twitter"
    link: ""
  - name: "📘 linkedin"
    link: ""
  - name: "⌨️ github"
    link: ""
  - name: "📸 instagram"
    link: ""
- contact

Originally I had these in the markdown, but I wanted the it in a list format without too much extra effort. If a person doesn’t use one of the social networks, I can just remove it from the list. Similarly, I can add one to the template or a person’s contact page without breaking anything.

The updated markdown template has new fields and is a bit more organized:

##  👤 (name:: {{title}})
(photo::  )

📛 (pronouns:: )
🔊 (pronunciation:: )
🕵️ (akas:: )
🎂 (birthday:: )

### contact information
📧 (email:: ) 
☎️ (phone:: )
📍 (location:: )
🔗 (website:: )

### professional information
🌐 (affiliations:: )
💼 (title:: )

### social presences

This is where the list of social networks comes into play. Using an inline Dataview query, I can populate a person’s various presences on the web regardless of how many entries there are:

`= join(map(this.socials, (x) => + ": " +, "<br>")`

All told, this doesn’t look like a big improvement over my original template.

Screenshot of a rendered contact for someone named Anem O&rsquo;ne

But, the magic comes out when I want to extract information. In my vault’s people folder, I have a file named _directory (the underscore keeps it on top!). All this file does is…compile a directory of the people in my contacts and displays a subset of the information that I specify:

TABLE WITHOUT ID AS name, photo, pronouns, title, email, tags
FROM "people" and #contact
SORT lower(name) ASC

That gives me a nice table view into my contacts.

Screenshot of a table of contacts displaying a link to each contact, their name, photo, pronouns, title, email, and tags

I used TABLE WITHOUT ID to create the table because the name of each file is the name of the contact, and I wanted to be able to make the heading say “name” instead of the default “File”. While the name field from a contact’s file will give you the name of the person, using gets you a clickable link to the contact’s file, so it’s good enough for me. Adding #contact to the FROM clause ensures that I don’t accidentally include any files that aren’t contacts, including the _directory file itself.

Now the unfortunate part of this exploration is that there’s no real way (that I’ve found) to retroactively apply templates to existing files. Updates to the template does not alter any pre-existing contacts. I can insert the updated version into existing contacts, but I have to manually move data into the new fields. This is something that I can live with, though, as a tradeoff for being able to fully customize my experience.