Return blocks, not pages, with a user-provided property

I’m trying to organise data by adding a user-made property “foo” with values “true”, “false”, “bar”. I add this property to pages, which I can easily query with a simple query using page-property foo.

But I also use this property in blocks. If I use property foo I get a mix of pages and blocks, but logseq returns the properties of the page, not the page name in the same column as the block contents, which makes it difficult to read. So I want a query that only returns blocks.

I tried looking for blocks with a parent (pages are blocks without a parent), but it’s not working well.

#+BEGIN_QUERY
{:title "'foo' blocks"
 :query [:find (pull ?b [*])
         :where
         [?b :block/parent ?p]
         [?p :block/content]
         [?b :block/content ?content]
         [?b :block/properties ?prop]
         [(get ?prop :foo) ?f]
         (or
           [(not= ?content "")]   ; requires blocks with parent content
           [(not= ?f "")]  ; not sure if this is working at all - I have a blank foo property and it is still being returned
         )
]
}
#+END_QUERY

This is successful in returning only non-page blocks, but it also omits blocks at the parent level of a page.

Can you provide a suggestion to improve the query?

  • include level 1 blocks on a page
  • omit empty “foo” properties

Welcome.

  • For blocks that are not pages: [?b :block/page]
  • For blocks with non-empty property foo:
    [?b :block/properties ?props]
    [(get ?props :foo) ?foo]
    (not [(= ?foo "")])
    
  • All in all:
    #+BEGIN_QUERY
    {:title "'foo' blocks"
     :query [:find (pull ?b [*])
        :where
        [?b :block/page]
        [?b :block/properties ?props]
        [(get ?props :foo) ?foo]
        (not [(= ?foo "")])
      ]
    }
    #+END_QUERY
    
1 Like

You actually get blocks specifically.
Page properties are also listed in blocks. Thus your query returns the block of page properties as it has the property you query for.
Because the block has no content other than properties, this is what is shown in the block column.

For a more visual example of what I mean, check out this post:

That’s resulting in the same thing I have where it is returning pages and blocks.

Ah, ok, that makes sense conceptually. I’m getting the block that is tagged. Sometimes the block is the page properties block.

And I fully support your preferences in that post. We need the concept of “metadata” so we can extend the idea of “page properties” to block in queries.

My next experiment is to see if I can use tags on blocks instead to accomplish what I want.

So, the crude alternative that seems to be working for me is to use 2 queries: one for page-properties foo and one for #foo tags and block properties where I provide the values “true/false/bar”.

  • In my experience:
    • what you have returns both blocks and pages
    • mine returns only blocks and not pages
  • You may double-check either:
    • that you are using the exact query
    • that the description of your question is accurate
      • Consider providing some example data, so as we all use the same.

As explained by Siferiax, it’s returning the page properties as a block. So, technically, you are correct; it’s returning blocks, not pages.

  • To exclude first blocks in pages:
    [?b :block/left ?left]
    (not [(= ?left ?p)])
    
  • All in all:
    #+BEGIN_QUERY
    {:title "'foo' blocks"
     :query [:find (pull ?b [*])
        :where
        [?b :block/page ?p]
        [?b :block/properties ?props]
        [(get ?props :foo) ?foo]
        (not [(= ?foo "")])
        [?b :block/left ?left]
        (not [(= ?left ?p)])
      ]
    }
    #+END_QUERY