Closed wuqui closed 3 years ago
Hey @wuqui
Right now links are not part of vulpea-note
hence vulpea-db-query
will not help here. Reason for that is simple - I never needed, this but if someone needs, that I am totally fine adding them (considering performance penalty is neglectable).
So back to your specific question. This library already provides a function to find notes linked to current note - vulpea-find-backlink
. If we look into its implementation, we can see that it uses org-roam-backlinks-get
:
So we can just combine it into solution thanks to existence of seq-intersection
. Let's say we want to find all notes that link note for Corinto grape (id feffc6de-9a35-449b-8470-e64b4f28832c
) and Nero d'Avola (id c9731b65-61f8-4007-9dbf-d54056f55cc4
). For simplicity it's going to show titles of notes that link them both.
(let* ((node1 (org-roam-populate
(org-roam-node-create :id "feffc6de-9a35-449b-8470-e64b4f28832c")))
(backlinks1 (seq-map #'org-roam-backlink-source-node
(org-roam-backlinks-get node1)))
(node2 (org-roam-populate
(org-roam-node-create :id "c9731b65-61f8-4007-9dbf-d54056f55cc4")))
(backlinks2 (seq-map #'org-roam-backlink-source-node
(org-roam-backlinks-get node2))))
(seq-intersection
(seq-map #'org-roam-node-title backlinks1)
(seq-map #'org-roam-node-title backlinks2)))
This returns the following list for me (first note is a description of wine that contains both grapes and the latter where I mention everything in one single journal note):
("Tenuta di Castellaro Nero Ossidiana 2015" "Saturday, 23 October 2021")
As opposed to this list, when I combine these two lists via seq-uniq
:
("Tenuta di Castellaro Nero Ossidiana 2015" "Tenuta di Castellaro Corinto 2017" "Saturday, 23 October 2021" "Cerasuolo di Vittoria DOCG" "Frappato" "Donnafugata Tancredi 2016" "Tasca Regaleali Nero d'Avola 2017" "Firriato Santagostino Baglio Soria Nero d'Avola Syrah 2014" "COS Pithos Rosso 2010" "Gulfi NeroSanlorè 2013" "Gulfi neroBaronj 2016" "Gulfi Nerojbleo 2009" ...)
As you can see, none of vulpea
functions are used here. Because org-roam
is powerful enough by itself. If backlinks are first class citizen in vulpea
(and again, if someone has the need for this I would take a look how to add them), the code would look like this:
(vulpea-db-query
(lambda (note)
(and (seq-contains-p (vulpea-note-backlinks note)
"feffc6de-9a35-449b-8470-e64b4f28832c")
(seq-contains-p (vulpea-note-backlinks note)
"c9731b65-61f8-4007-9dbf-d54056f55cc4"))))
Hope that helps.
Brilliant, thanks for this quick and excellent answer!
How could I turn this into an (interactive) function I can use? So from a user perspective, for this to be practically useful, you would probably want to be able to call a function and then interactively select >= 1 node and get a list of notes back?
I think this should be incredibly useful for lots of people in different use cases. I guess the fact that queries like this are very popular in Roam Research and logseq would be some empirical evidence that it's worth building something like this for org-roam.
Brilliant, thanks for this quick and excellent answer!
Glad you find it useful.
get a list of notes back
What do you mean by 'back'? :) Like, in interactive use there is no point in returning anything from a function as it's interactive use. But let me show you several examples.
First, here is a function that returns a list of backlinks for a given list of notes.
(defun vulpea-backlinks-many (notes)
"Return notes that link to all NOTES at the same time."
(let* ((blinks-all
(seq-map
(lambda (note)
(seq-map
#'org-roam-backlink-source-node
(org-roam-backlinks-get
(org-roam-populate
(org-roam-node-create :id (vulpea-note-id note))))))
notes)))
(seq-reduce
(lambda (r e)
(seq-intersection
r e
(lambda (a b)
(string-equal (org-roam-node-id a)
(org-roam-node-id b)))))
blinks-all
(seq-uniq (apply #'append blinks-all)))))
Non-interactive usage example:
ELISP> (seq-map
#'vulpea-note-title
(vulpea-backlinks-many
(list
(vulpea-db-get-by-id "feffc6de-9a35-449b-8470-e64b4f28832c")
(vulpea-db-get-by-id "c9731b65-61f8-4007-9dbf-d54056f55cc4"))))
("Tenuta di Castellaro Nero Ossidiana 2015" "Saturday, 23 October 2021")
Now we ca use it in many ways. For example, this will allow to interactively select several notes, and then select a title among these titles:
(defun select-backlinks-many ()
"It's hard to explain."
(interactive)
(let* ((notes (vulpea-utils-collect-while
#'vulpea-select
nil
"Note" :require-match t))
(blinks (vulpea-backlinks-many notes)))
(completing-read
"Blacklink: "
(seq-map #'vulpea-note-title blinks))))
It uses a helper function from vulpea
:
Basically, you initially select as many notes as you wish and stop this by pressing C-g
, and then it will prompt for backlinks.
If you wish, I can send an example where you select and visit backlink instead of just returning the name 😸
I'm very interested in being able to query my org-roam DB like with
org-ql
orlogseq
. I came across your packagevulpea
, but I didn't find any documentation on how to query the database, ideally beginner-friendly?For example, I would like to do queries that return a list of all nodes that link to nodes A and B. Is something like this possible?