List all blocks without a page reference (orphans)

Would be great to surface “orphan” blocks, tasks or not, that would inevitably fall through the cracks otherwise. How would you extend this to any block that doesn’t have a page reference other than the one it’s in, the task page, and quick capture?

Edit: Just realized that the priorities A, B, C are also page references to exclude.

This is probably not possible, but is there any way to kind of “put on hold” the live query while making edits to a block? I used your exact query above to have a list of tasks I can tag but the moment I add one tag, the query updates right there and the block disappears before I can add more tags (understandably).

My workaround has been to view it as a table and just click on the task which automatically opens on the right panel where I can tag at will.

We just need to add more things the block should not have as a reference.
We might need separate not clauses for that.
Basic structure would be:

(not
  [?var :block/name "pagename lower case"]
  [?b :block/path-refs ?var]
)

Whereby ?var is a unique name that starts with ?.
I see that in my example I used the structure of [(!= )]. Either should work.

I didn’t want to leave you hanging. Just know I’m doing this from memory.

No, I think your approach is best.
I would also sometimes just click the bullet to focus into the block for editing. That’s an alternative.
There’s no way to stop the updating behavior.
In the use case of checking off tasks, you would want to task to immediately get off the list.

1 Like

Sorry Siferiax, my description was confusing; I actually meant include. Upon further consideration, the query I’m after should show all blocks (with at least one character) from journals that don’t have any page reference at all, other than the one they’re in, or have any the following at most:

-TODO
-quick capture
-A, B, or C priority (with or without task)
-SCHEDULE or DEADLINE (with or without task) should they also be “secretly” a page reference. I want to pull blocks that might have a date, task or not, but no real page ref.

This would be a way to catch early all orphan blocks including those that, despite having a task, priority, a date, or the quick capture tag, don’t have a real page reference about what it is related to otherwise. This will give me a catch-all net to make sure whatever I add to Logseq is properly stored, retrieved, and acted on later.

Thanks! Let me know if you would like me to open a new thread for this.

I understood you correctly… but the answer to your question gave me a headache :smiley:

So it wasn’t quite so simple as I initially thought. As in I was going to “just” give you the full query… but as I was writing it in Logseq I got some… unexpected results lol!

So let’s break down your question.

  1. The block needs to lack any sort of reference
  2. TODO etc. give a block a reference
  3. We still want to see those blocks that have build in pages as a reference, but not anything else. (I’m just saying build in for easy of writing)

To do this, we need to define what we don’t want as a subset and then subtract it.

  • The block has a reference to a task state
  • The block has a reference to a priority state
  • The block has a reference to the quick capture page

Those are 3 distinct subsets. We wish to subtract those from the subset that is,

  • The block has a reference.

And then we want to subtract all of that from the blocks we initially selected. (all blocks in past journals)

This got me to the following query:

#+BEGIN_QUERY
    {:title [:h3 "☑ Unplanned"]
    :query [:find (pull ?b [*])
    :in $ ?day
    :where
      [?p :block/journal-day ?d]
      [(< ?d ?day)]
      [?b :block/page ?p]
      (not 
        [?b :block/path-refs ?r]
        [(!= ?p ?r)]
        (not
          [?b :block/marker ?mark]
          [?m :block/original-name ?mark]
          [(= ?m ?r)]
        )
        (not
          [?b :block/priority ?priority]
          [?prio :block/original-name ?priority]
          [(= ?prio ?r)]
        )
        (not
          [?qc :block/name "quick capture"]
          [(= ?qc ?r)]
        )
      )
    ]
    :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/page :block/journal-day])) result))
    :inputs [:today]
    :table-view? false
    :breadcrumb-show? true
    :collapsed? false
    }
#+END_QUERY

Which results in:

(I had to limit my query to today’s journal to not get the whole test graph I have :joy:)

1 Like

Wait are we still talking path-refs? Cause I may have overlooked that :smiley:
Let me… correct that…

Fabulous!! Wow. Thank you so much!!

I was horrified at the thousands of results (a telling sign of sloppy tagging :face_with_open_eyes_and_hand_over_mouth: …). I noticed, though, that the query is displaying blocks we wouldn’t want to see.
Q1. How would we remove the following results?

  • blanks/empty blocks
  • line breaks ---
  • DONE, and CANCELLED/CANCELED tasks.

The following might be trickier so please don’t sweat it too much; this query is already fantastic! So I also noticed that the query doesn´t catch blocks with properties, even if they’re empty. For those blocks that meet the above criteria to be displayed but happen to have properties:
Q2. How can the query include orphan blocks that meet the criteria already established BUT also have properties?

  • IF they do, I would want to display only the ones that don’t have a tags:: property or have a blank one.
  • The other properties could even have page references but I would still want to consider them orphans since they’re probably auto-filled.

Examples:

  • a simple block that was created through a template but was never referenced. Has a blank tags property. Should be included in the results.
    tags::
    author::
    source::

  • a simple block that was never referenced but has properties, even with page references (usually auto generated), but no “tags::” property per se. Should be included in the results.
    date-saved:: [[Apr 10th, 2024]]
    source::

I’m aware Q2 might be impossible or too involved to do. You would have to make a distinction between blocks not having page references on their “body” vs in their properties.

Thanks again!!

  • Excluding unwanted results by filtering is fair.
  • Including different results in the same query is not advisable.
    • It is better to use multiple queries, each one including a specific case.
      • Applying the same exclusions to all of them is relatively simple.
1 Like

Relevant: Query to find orphan blocks?

1 Like

This is a matter of just adding more exclusions to our query:

#+BEGIN_QUERY
    {:title [:h3 "☑ Unplanned"]
    :query [:find (pull ?b [*])
    :in $ ?day
    :where
      [?p :block/journal-day ?d]
      [(< ?d ?day)]
      [?b :block/page ?p]
      [?b :block/content ?c] ;get the content of the block
      (not [(contains? #{"" "---"} ?c)]) ;block content is not "" (empty string) or ---
      (not 
        [?b :block/path-refs ?r]
        [(!= ?p ?r)]
        (not
          [?b :block/marker ?mark]
          (not [(contains? #{"DONE" "CANCELLED" "CANCELED"} ?mark)]) ;the task state is not DONE, CANCELLED or CANCELED
          [?m :block/original-name ?mark]
          [(= ?m ?r)]
        )
        (not
          [?b :block/priority ?priority]
          [?prio :block/original-name ?priority]
          [(= ?prio ?r)]
        )
        (not
          [?qc :block/name "quick capture"]
          [(= ?qc ?r)]
        )
      )
    ]
    :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/page :block/journal-day])) result))
    :inputs [:today]
    :table-view? false
    :breadcrumb-show? true
    :collapsed? false
    }
#+END_QUERY

This should give you a nice idea from which to build on.

It should?


Properties have nothing to do with references, so unless the reference is in the property the query will show the block.

This is the more tricky question. We don’t know what keys we have and for our (get ) we need to give the key. I don’t know of a way to do this in datalog honestly. So this is a question that is beyond my knowledge :slight_smile:

We can make a query that gives blocks with properties and regardless of reference that is missing the tags:: property or has an empty one.

#+BEGIN_QUERY
    {:title [:h3 "☑ Unplanned"]
    :query [:find (pull ?b [*])
    :in $ ?day
    :where
      [?p :block/journal-day ?d]
      [(< ?d ?day)]
      [?b :block/page ?p]
      [?b :block/properties ?prop]
      (not [(empty? ?prop)]) ;it actually has properties, blocks have an empty property list by default apparently...
      (or-join [?prop]
        [(missing? $ ?prop :tags)]
        (and
          [(get ?prop :tags) ?tags]
          [(= ?tags "")]
        )
      )
    ]
    :result-transform (fn [result] (sort-by (fn [r] (get-in r [:block/page :block/journal-day])) result))
    :inputs [:today]
    :table-view? false
    :breadcrumb-show? true
    :collapsed? false
    }
#+END_QUERY
1 Like