Single query for both page properties and block properties

Apologies if there is already information on this. The closest I could find was from this thread:

The issue:

If I have some blocks in this format:

  • type:: quotation
    • some text here
      • author

I also have some pages in this format:

  • type:: quotation
  • some text here
    • author

I’d like a query to display a list of the “some text here” blocks and the child blocks (preferably without the property block).

This is my current query:

#+BEGIN_QUERY
{
:title [:h3 "Quotations"]
:query [:find (pull ?b [*])
:where
  [?b :block/page ?p]
  [?b :block/properties ?props]
  [(get ?props :type) ?type]
  (or 
    [(contains? #{"quotation"} ?type)]
    [(= "quotation" ?type)]
  )
]
}
#+END_QUERY

For blocks, it works well, and shows the quotation text (although I’d prefer not to see the type:: quotation block.

For pages, since type:: quotation is a sibling of the quotation text, the query only shows the page title and the type:: quotation block.

Is there a way to handle this discrepancy, while still making use of top-level (frontmatter) properties for pages that are quotations? Or does @Siferiax 's comment quoted above mean that there really isn’t a way to handle it elegantly?

For the first case you can use [?x :block/parent ?b] and return ?x instead.

For the second it depends on the page.
If it is a page full of quotations and you wish to have all of them. Then you can do so with an or-join in the same query I suppose.
As you wish for either:

  • a child of a block with type quotations
  • a top level block on a page with type quotations

For both you’d want to use the :block/parent attribute. But one points toward the page and the other the block.
I’ll have to experiment to see what can be done.

1 Like

Thanks so much!

I’ve been struggling with this very basic part of Datalog. Is returning the parent as simple as ending the query with your example [?x :block/parent ?b] ?

It used to be a full page of quotations, but since Logseq’s find-in-page function is crippled by lazy loading, I split it into multiple single pages.

Now each page has a top block with the page property, followed by a sibling block with the quotation. I had assumed that Logseq queries would see the page property as truly a page property, and so would list the page’s contents when the property matches. Instead, it just seems to see it as a normal block property, so the sibling block with the quotation content isn’t included in the query.

I suppose I can also just indent all of those quotations that are in their own pages, inside the property block, so that they match quotations that are, for example, in journal pages or elsewhere.

1 Like

No. What gets returned is determined by what is defined in the :find clause.
So either change the ?b to ?x there, or change the variable naming in the rest of your query.

Yes and no :slight_smile:
I found an attribute that gets added for blocks that are page properties.
But blocks with page properties are still just that, blocks.
We can “force” Logseq to return the page, but then you get the page information and not the blocks on that page.

So I fiddled around with your request a little.
Here’s what I came up with:

#+BEGIN_QUERY
{:title [:h3 "Quotations"]
 :query [:find (pull ?b [*])
  :where
;get blocks of type quotations (where quotations is plain text)
   [?x :block/properties ?props]
   [(get ?props :type) ?type]
   [(= ?type "quotations")]
   [?x :block/page ?p]
;either...
   (or
;the block is a pre-block (page properties) and so the quotation is a block on the same page, excluding the properties block
     (and
       [?x :block/pre-block? true]
       [?b :block/page ?p]
       [(!= ?b ?x)]
     )
;or the block has the properties block as its parent.
     [?b :block/parent ?x]
   )
 ]
 :breadcrumb-show? false ;don't show the breadcrumb (?x in the case of it being the parent block)
}
#+END_QUERY

2 Likes

Gotcha. I must have tested some badly formed query and incorrectly concluded that this wasn’t the case.

This is brilliant! :partying_face:

Thanks for taking the time to explain so clearly, and providing this code. The :block/pre-block as a test for page-properties is perfect.

(At first it didn’t work, because my page properties had a preceding bullet - , so weren’t identified as pre-blocks. It must have been an oversight when making batch changes in VSCode.)

So worth noting for others: page properties should not be bulleted (and they aren’t, because Logseq recognizes the :: syntax)

1 Like