Last time I discussed a topic / person in my dailies

Hi all,

I’m starting to move over more and more of my things from (xyz) to Obsidian and I think it’s great - thank you for it!

In my dailies, I sometimes mention people using links. This works great and I can easily see for a single person when we were in touch. As next step, I would like to get an overview of when is the last time I mentioned somebody, so that I could regularly catch up if it has been a long time.

I have played a bit with dataview but did not come very far:

TABLE file.name FROM "journal" 
WHERE contains(file.outlinks.file.name, "Person")

This gives me a table with all dates when I mentioned “Person”.

Several things are still lacking:

  • sort out the last time (i.e. largest file name)
  • automate this a bit more, e.g. by tagging people which should be included in the list

Any pointers or ideas are highly apprecicated!

Best
Sebastian

1 Like

Hi.

  1. First, please clarify this: you mention people as a link to person file - [[John]] - and these files exists in your vault?
    If yes, you can use a query like this:
```dataview
TABLE file.name
FROM [[John]] AND "journal"
```
  1. Why you want TABLE file.name? This gives you two columns with the same content: one in link format and other as a string…

  2. You want to sort by the daily note date? How is the format of your daily notes titles?

  3. What do you mean by “automate this a bit more, e.g. by tagging people which should be included in the list”? A previous list of “persons” to include in the query? (table is the result of the query, a dynamic table…)

Hello,

I do the same and I have decided to use a defined, seperate field to note all the contacts I had with people, which subject we discussed, ect.

The format for that is like this …

**subject**:: had a meeting with [[John Doe]] about subject XYZ

I can have multiple subject entries on the same page. With the query options in Obsidian you can only show the one’s where that specific person is used.

The query looks like this…

```query
--path:daily line:("[[John Doe]]" **subject**::)

The great part is I also have a “person” template in which I use {{title}} instead of [[John Doe]]. When I create a new person page for a new contact the correct query is inserted in that person’s page.

I also tried dataview (hence the double :: behind subject) but I did not manage to get that working with showing all subjects from the daily page although only one contained the person’s name. The native query does that perfectly.

About this question, you can try the function filter() in this way.

```dataview
TABLE subject, filter(subject, (s) => contains(s, "[[John Doe]]")) as "subject filtered"
WHERE subject
```

(the columns “subject” vs “subject-filtered” are to comparative purposes)

It works?

Hi,

thanks for taking the time to reply and sorry for being not clear enough. Let me describe my use case in a little more detail.

Suppose I have the following structure:

people/
    John.md
        with tag: @follow-up
    Mary.md
        with tag: @follow-up
    Alex.md
        without tags

journal/
    2021-11-11.md
        with content: Met [[John]] and [[Mary]] once again. 
    2021-11-12.md
        with content: Was introduced to [[Alex]]. I don't like him.
    2021-11-13.md
        with content: Had a pleasant call with [[Mary]].

What I now would like to extract from this structure is the following table:

Person   | Last Contact
-------------------------
[[John]] | [[2021-11-11]]
[[Mary]] | [[2021-11-13]]

Note that I do not want [[Alex]] to show up and that I want to have latest contact with [[Mary]]. And to make the implicit assumption more explicit: ideally, the table would auto-populate with new people added to my vault if they have the matching tag.

I hope this clarifies your questions 1, 2, and 4.

Regarding 3: the title of my notes is: "# YYYY-MM-DD, DAY_OF_WEEK

Thanks
Sebastian

That is also a good idea, thanks for bringing it up. Will look into that approach as well.

Hi @Bayerse.

Let’s try to find a way to solve your dataview query with all your requisites.

I made a test with your structure (“people” and “journal” files) and my first observation is: instead of @follow-up I used the tag #follow-up, because the symbol @ at the start of a tag give me a error (I suppose that is not allowed in tags).

The general structure of the query could be this:

```dataview
TABLE WITHOUT ID file.link AS "Person", file.inlinks AS "Last Contact"
FROM #follow-up
```

This query gives us the list of people with the tag #follow-up and the links of the daily notes where each person is mentioned. Results like this:

But you want to filter the list in “Last Contact” only to the last daily note where person is mentioned. To do that, I suggest in first place sort “file.inlinks”, then reverse this order (the most recent in first place) and finally filter the list to present only the first object in that list (using [0]). I.e., this query:

```dataview
TABLE WITHOUT ID file.link AS "Person", reverse(sort(file.inlinks))[0] AS "Last Contact"
FROM #follow-up
```

Finally, we need to sort the results by the most recent contact:

```dataview
TABLE WITHOUT ID file.link AS "Person", reverse(sort(file.inlinks))[0] AS "Last Contact"
FROM #follow-up
SORT file.inlinks DESC
```

Is this what you want?

3 Likes

Very nice @mnvwvnm, thanks! I tag people notes as #People and have a general #favourites tag. So I’ll pull from those.

I might make a couple of other headings, like

  1. Days since last contact
  2. If days since last contact is >60 days, contact now.

Something like:

```dataview
TABLE WITHOUT ID
	file.link AS "Person",
	reverse(sort(file.inlinks))[0] AS "Last Contact",
	date(today) - date(reverse(sort(file.inlinks))[0]) AS "Days since last contact",
	choice(date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(60 days), "Contact now", " ") AS "Call"
FROM #follow-up
SORT file.inlinks DESC
```

1 Like

That works like a charm! Thank you very much!

I like the idea with the call reminder very much as well. Would it perhaps be possible to have dynamic frequencies using hierarchical tags?

Could you explain more?

Say I want to contact some relative once every quarter and a close friend every other week. Then it would be beneficial to have that information in the tag, e.g.

#follow-up/14
#follow-up/90

And then use the second level of the tag as reminder frequency as in above snippet.

But if the reminder depends on the “days since last contact”, the relation is direct with the date of the last daily note, not with person file. (but if the reminder is only a simple tag, without any relation with elapsed time, you just need to present the tag in the table)

The function choice() works in this way:

choice(argument, "if-argument-true-then-present-this", "if-false-present-this")

If you want different reminders (if 14 days or more since last contact show “contact now”; if 30 days or more since last contact show “contact now”, etc), with simple dataview DQL (javascript not my ground), it’s necessary to create different columns for each type of reminder.

(…or I need to go deeper in my basic knowledge and find another way that because at the moment doesn’t seem very obvious to me…)

Bloody outstanding @mnvwvnm!

@Bayerse It would probably be better to have a Contact Frequency field where you insert “60 days” or “60 years” depending if the person is your parent or parent in law!

I think you could substitute >= dur(file.contact-frequency) in the “Call” column.

… Nope, that gives an error, I’m not sure why it doesn’t recognise the file.field duration… @mnvwvnm, are you still having fun here? :joy:

1 Like

Wait…
Going in other direction and using too your “frequency” tags:

#follow-up/14
#follow-up/60

In person file you just need to use one tag. #follow-up/14 include #follow-up

Then, I can create the “argument” in choice() in this way:

for 14 days: "14 days from last contact" AND "contains tag #follow-up/14"

(date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(14 days) AND contains(file.tags, "follow-up/14"))

for 60 days: "60 days from last contact" AND "contains tag #follow-up/60"

(date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(60 days) AND contains(file.tags, "follow-up/60"))

joining both with `OR` condition

(date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(14 days) AND contains(file.tags, "follow-up/14")) OR (date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(60 days) AND contains(file.tags, "follow-up/60"))

Now the query:

```dataview
TABLE WITHOUT ID
	file.link AS "Person",
	reverse(sort(file.inlinks))[0] AS "Last Contact",
	date(today) - date(reverse(sort(file.inlinks))[0]) AS "Days since last contact",
	choice((date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(14 days) AND contains(file.tags, "follow-up/14")) OR (date(today) - date(reverse(sort(file.inlinks))[0]) >= dur(60 days) AND contains(file.tags, "follow-up/60")), "Contact now", " ") AS "Call"
FROM #follow-up
SORT file.inlinks DESC
```

please try and tell if works (I did only one fast test).

Found it!

If the person page has contact-frequency field, with 30 days, then this works.

TABLE WITHOUT ID
	file.link AS "Person",
	reverse(sort(file.inlinks))[0] AS "Last Contact",
	date(today) - date(reverse(sort(file.inlinks))[0]) AS "Days since last contact",
	choice(date(today) - date(reverse(sort(file.inlinks))[0]) >= contact-frequency), "Contact now", " ") AS "Call"
FROM #follow-up
SORT file.inlinks DESC
2 Likes

This is a much more clever approach! (I give up in giving more help in DQL :slight_smile: )

But this solution implies you have the field contact-frequency in all the person files. If not, where no field (or value) the query returns always “Contact now”. It’s necessary to exclude null cases.

Maybe with the function default():


```dataview
TABLE WITHOUT ID
	file.link AS "Person",
	reverse(sort(file.inlinks))[0] AS "Last Contact",
	date(today) - date(reverse(sort(file.inlinks))[0]) AS "Days since last contact",
	choice(date(today) - date(reverse(sort(file.inlinks))[0]) >= default(contact-frequency, " "), "Contact now", " ") AS "Call"
FROM #follow-up
SORT file.inlinks DESC
```
1 Like

Hi @mnvwvnm,

I wonder if it is possible to only select file inlinks that have the #journal tag.

We don’t want file inlinks from any random file, because

  1. (I believe that) notes that don’t have a YYYY-MM-DD title will not have a date(reverse(sort(file.inlinks))[0])attribute.
    • And therefore every [[Person Note]] that is linked to from a non-YYYY-MM-DD will be excluded. I think that’s what I am seeing in my test.
  2. We could change it to date(reverse(sort(file.inlinks.file.day))[0]) or cday, but it wouldn’t help, because the reverse sorting would put any non-YYYY-MM-DD (word title) files first, and we wouldn’t get a list of the recent journal dates… which is what we’re are wanting!

Good luck! :slight_smile:

Wow! You guys are awesome! Thank you so much for your help, @mnvwvnm and @dryice! It’s amazing what you can do with dataview.

Now I just need to find a way how to differentiate between true contacts and mentions, e.g.

Called [[John]]. He said that [[Mary]] is not so well these days.

In that case, John would be a proper contact, but [[Mary]] not. But I think this is beyond the scope of this thread.