Load page associated with a block's property

I have a query that looks like:

:find (pull ?b [...]) (pull ?p [...])
:where
	(or-join [?b ?p]
		(and
			[?b :block/properties ?bp]
			[(get ?bp :project) ?proj]
			[?p :block/original-name ?projName]
			[(contains? ?proj ?projName)]
		)
		[?b :block/page ?p] ;; If I comment this out, it loads the correct page when linked via :project, but not otherwise
	)
	;; there's more going on in this query, context below

The idea is that I want to load [block, page] tuples, where the page is either a page linked in a “project” property, or if that doesn’t exist, just the page the block is on.

As an illustrative example:

Page: Journal 2024-02-07
- TODO Do a thing
  project:: [[Some Project]]

Page: Some Project
- TODO Do another thing

My query should return [[Do a thing, Some Project], [Do another thing, Some Project]]. What it currently returns is [[Do a thing, 2024-02-07], [Do another thing, Some Project]].

I could have sworn this incantation worked at some point, but it isn’t working at present (I’m on 0.10.5). I’ve written a ton of Datascript queries at this point, but unfortunately still have no idea what I’m doing, especially with or-join.

Context: I’ve built a terminal task management tool on top of Logseq (via the HTTP API, repo) inspired by GTD (and Everdo in particular).

You can see the code/query in question here, and other queries in the project here, here, and here.

Any help is much appreciated!

  • Your description is hard to follow.
  • If I understand, your problem is the following:
    • In my tests, your query returns both:
      • the desired form [Do a thing, Some Project]
      • the non-desired form [Do a thing, 2024-02-07]
    • because all the blocks that satisfy the first part of the or-join-clause, they also satisfy its second part
      • so they appear twice as semi-duplicates (i.e. same block, different page)
    • If that is the case and you want to remove the non-desired form, should explicitly filter the second part like this:
      (and
        [?b :block/page ?p]
        (not
          [?b :block/properties ?bp]
          [(get ?bp :project)]
        )
      )
      
1 Like

You’ve understood well and your solution works perfectly, thanks for your help!

The part that made this confusing (which I did a poor job of explaining) is that I’m loading these results via the HTTP API, and storing them in a map keyed by block UUID, and it just so happened the non-desired form was ordered second consistently, and so was overwriting the correct one.

I had come across the “multiple results returned for one block”, but my understanding of or-join (and Datascript in general, really) is shoddy enough that I didn’t really know why or how to fix it.