Last time I discussed a topic / person in my dailies

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.

Well, a challenge is a challenge:slight_smile:

But please be gentle and don’t push too much because I’m not a coder/programmer or similar (tech isn’t my field). I don’t even know how the script works (in code language and logic sense) and I’m a zero in javascript (which would certainly be more useful for solving this challenge).

But i’ll try my best, working only with DQL, by “try-error” method.

After some hard work, considering that commands are executed in order and can be used multiple times, I tried to play with FLATTEN, SORT, WHERE and GROUP BY.

I’m not sure if I understand well how flatten/group works (because the “rows” - here’s a proof of lack of knowledge on the language side and logic of the code), and I don’t know if the query is “bulletproof” or if it has some problems because the tests were limited.

Another thing. The query proposal implies this condition: your notes with tag #journal works like daily notes, i.e., the date valid to the query is the date that the file was created. This means that for the query the content is added in the day you created the file.

That said, try this:

```dataview
TABLE WITHOUT ID
	Person,
	rows.IN[0] + "<br>" + "<span style='font-size:13'>(" + dateformat(reverse(sort(rows.IN.file.ctime))[0], "yyyy-MM-dd") + " )</span>" as "Last Contact (date)",
	date(today) - reverse(sort(rows.IN.file.cday))[0] AS "Days since last contact",
	choice(date(today) - reverse(sort(rows.IN.file.cday))[0] >= default(Person.contact-frequency, " "), "Contact now", " ") AS "Call"
FROM #follow-up
FLATTEN file.inlinks as IN
SORT IN.file.ctime DESC
WHERE contains(IN.file.tags, "#journal")
GROUP BY file.link AS Person
SORT reverse(sort(rows.IN.file.ctime)) DESC
```

EDIT: I think the last SORT can be more simple, just:

SORT rows.IN.file.ctime DESC
2 Likes

In that case I think you need to separate the way you mention people.
Taking your example, you can try dataview in-line field to “mention”. Something like:

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

Notes:

  1. For in-line fields in dataview you can use two syntaxes: [key:: value] or (key:: value). In dataview settings you can enable “Inline Field Highlighting” and see the diferences between two (in the second syntax the “key” disappears in preview mode, presenting only the “value”)
  2. But maybe you want a link in Mary… But to differentiate between true contacts and mentions, you need to work with mention not as true backlink (identified as “outlink” or “inlink”). To do that, let’s create a (non)link with an inline-query inside the field:
Called [[John]]. He said that (mention:: `=link("Mary")`) is not so well these days.

(if enable “Inline Field Highlighting”)
image

  1. With this solution, this “mention” isn’t considered as a backlink to [[Mary]]. But maybe you want this list of mentions inside [[Mary]] file to have a list with all “mentions”. For that you can use this query (valid to all people file, because “this.file.name”):
## mentions
```dataview
LIST
WHERE contains(mention, this.file.name)
```
2 Likes

Great solution, and estremamente raffinata !.
I’ll grab some hint in order to populate my next Dataview queries.
Thanks @mnvwvnm!!!

1 Like

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