Query based on MOC-Page (Map of Content)

  • Hello everyone,

    I’m new to logseq and I really like the idea of it in general. As I see, many other users are also missing some possibilities to structure tags (pages) hierarchically. The graph dosen’t seem to be very helpful for my purposes.

    I fancy with the idea of alex0 to create a MOC-Page with an index. What I’m still missing then, is an easy way to review my data from a higher point of view within my structure. For example I would like to see all my journal entries relating to my family, even if they are only referenced to specific persons.

    Therefore I tried to create a dynamic advanced query, that goes to my MOC-Page and searches for the current-page in the index. Then it should find all the children blocks in the index and search for blocks that are referencing to the children blocks.

    After days of research and trial and error I got it nearly working. But I guess, I’m missing the last puzzle piece. Can you maybe give me the vital hint, to get it running? The lines where I’m struggeling are commented in the code.

  • testpage.md
    - Some Info about my [[family]]
    	- Some Subtext
    	- Even more
    -
    - Some Info about my [[brother]]
    	- asdfdsfsdfsd
    	- saasdfsdfsdf
    -
    - Some Info about [[stocks]]
    	- adsdadfsdfsdferfe
    	- aefsrgthzjj
    -
    - Some Info about my [[parents]]
    	- sfksjflkejsifeajofsf
    -
    - Some Info about my [[dad]]
    	- sfserfgrgththjzrth
    -
    - Some random Note without reference
    
  • moc.md 
    - index
    	- [[personal]]
    		- [[family]]
    			- [[brother]]
    			- [[parents]]
    				- [[mom]]
    				- [[dad]]
    			- [[wife]]
    		- [[friends]]
    			- [[person C]]
    			- [[person D]]
    	- [[finances]]
    		- [[stocks]]
    			- [[stock A]]
    				- [[reports]]
    
  • family.md
    
    #+BEGIN_QUERY
    {:title ["References to current page and its children from MOC"]
    :query [:find (pull ?child [*])    ;->Output of ?parref or ?child works fine. Output of ?b does not.
    :in $ ?current %
    :where
    ;
    ;Output blocks must have same references as child-blocks
    ;[?b :block/refs ?child] -> This does not seem to work and I don't understand why.
    ;
    ;But not the ones from "moc" page itself
    ;[?b :block/page ?page]
    ;(not[?page :block/name "moc"])
    ;
    ;Parent-block has to be found on "moc" page
    [?parref :block/page ?parpage]
    [?parpage :block/name "moc"]
    ;
    ;And has to have the name of the current page
    [?par :block/name ?current]
    ;
    ;Reference of the parent-block
    [?parref :block/refs ?par]
    ;
    ;Find children of parent-block
    (get-children ?parref ?child)
    ]
    :rules
    [
    [
    (get-children ?parref ?child)
    [?child :block/parent ?parref]
    ]
    [
    (get-children ?parref ?child)
    [?t :block/parent ?parref]
    (get-children ?t ?child)
    ]
    ]
    :inputs [:current-page]
    :remove-block-children? true ;-> This does not seem to have any effect. When I set output to ?parref it shows me all children anyway. In list view it shows only the parent-block as supposed.
    :breadcrumb-show? false
    }
    #+END_QUERY
    
2 Likes

@Siferiax built something like that (a dynamic query that updates its results according to references in a list of TODOs: marking the TODOs as DONE updates the query accordingly).

1 Like

Welcome.

  • Concerning the line that doesn’t work: [?b :block/refs ?child]
    • It is meant for blocks (e.g. in testpage.md) referencing some page.
      • That page is meant to be also referenced in the MOC-Page.
  • However, the variable ?child doesn’t hold a page, but a block within the MOC-Page.
    • And thus no results are found.
  • Therefore, one more step is needed to extract the page out of the block in the MOC-Page, e.g.:
    [?child :block/refs ?child-page]
    [?b :block/refs ?child-page]
    
3 Likes

That works perfectly! Thank you very much for the quick solution!

Now I can either put:

[?b :block/refs ?child-page]

to get all referenced blocks to the child pages.

Or I can put:

[?b :block/refs ?par]

to get all referenced blocks to the parent-page.

What would be the trick to get all referenced blocks to the child-pages and the parent-page. Is there a way to merge it? Do I need an or-join to do that?

Here is the updated query, working for referenced child blocks:

#+BEGIN_QUERY
{:title [:b "References to current page and its children from MOC"]
:query [:find (pull ?b [*])
:in $ ?current %
:where
;
[?b :block/refs ?child-page]
;
;But not the ones from "moc" page itself
[?b :block/page ?page]
(not[?page :block/name "moc"])
;
;Parent-block has to be found on "moc" page
[?parref :block/page ?parpage]
[?parpage :block/name "moc"]
;
;And has to have the name of the current page
[?par :block/name ?current]
;
;Reference of the parent-block
[?parref :block/refs ?par]
;
;Extract child-page out of child
[?child :block/refs ?child-page]
;
;Find children of parent-block
(get-children ?parref ?child)
]
:rules
[
[
(get-children ?parref ?child)
[?child :block/parent ?parref]
]
[
(get-children ?parref ?child)
[?t :block/parent ?parref]
(get-children ?t ?child)
]
]
:inputs [:current-page]
}
#+END_QUERY
1 Like

Works perfectly and a brillant addition, this should be built into Logseq with the default Contents.md in my opinion!

1 Like

Yes that’s what you would need.

Also as a more general comment, I would consider changing the clause order a little bit. For performance reasons you want to consider making the dataset as small as possible, as soon as possible.
For example ?current is already defined to 1 value, in contrast with ?b and ?child-page in your first clause. This first clause will get all blocks on all pages, which as the graph grows slows down the query significantly.

2 Likes