How to query in a forall logic?

How to query in a forall logic?

Hi guys, I’m facing an issue while attempting to write an advanced query following a for-all (for-each / for-any) logic that: given x, for any y, if there is a relationship R between x and y, then y has the property P. This is equivalent to saying that there is no y who shares a relationship R with x but lacks the property P.

An example scenario is:
suppose I only have two pages as follows:

block-exists
    - <empty block>
    - #query-tag
    - <empty block>
    
block-forall
    - #query-tag 
    - #query-tag
    - #query-tag

The goal is to (a) find all pages x such that every block y of the page has the tag #query-tag,
So a right query should result in a page list that only contains the page block-forall.

I am new to the datalog query language and don’t know how to directly do the task, but I learn that the equivalent way is to
(b) find all pages x excluding the ones who do have a block y without the tag #query-tag.
So my current query is

#+BEGIN_QUERY
{
:query [
    :find (pull ?p [:block/name]) 
    :where 
        [?p :block/name]
        (not-join [?p]
            [?b :block/page ?p] 
            (not [?b :block/refs [:block/name "query-tag"]])
            )
    ]
}                           
#+END_QUERY

This query does not work as expected.

The other similar scenario is to find all empty pages. By an empty page, I mean the page who either does not have any content or contains one property block as the content.
I know how to write a query of finding non-empty pages (as follows), but failed to write a query to do the opposite, too.

#+BEGIN_QUERY
{
:query [
    :find (pull ?p [:block/name]) 
    :in $
    :where 
        [?p :block/name]                  ;; all pages
        [?p :block/journal? false]        ;; not journal
        
        [?b :block/page ?p]               ;; blocks of the page
        [(get-else $ ?b :block/pre-block? false) ?first]  
        [(= ?first false)]
        [?b :block/content ?content]      ;; block content
        [(not= ?content "")]
    ]
}                           
#+END_QUERY

I have searched forum and datomic docs but couldn’t identify the problem. Any insights or suggestions? I would greatly appreciate your assistance. Thank you!
Relevant Link: Datalog: does every value for a given entity attribute exactly match a given set? - #5 by dustingetz - General - Datomic Developers

Original post:
[s] Hi guys, I’m facing an issue while attempting to write an advanced query following a forall logic x: ∀y, relation(x,y) <=> x: ¬(∃y, ¬relation(x,y)) . The scenario involves two pages as below:

block-exists
    - <empty block>
    - #query-tag
    - <empty block>
    
block-forall
    - #query-tag 
    - #query-tag
    - #query-tag

My goal is to create a list of pages with blocks each tagged with “#query-tag”.
The result should be the “block-forall” page in the given scenario.
However, my current query did not work as expected (returning a list many other irrelavant pages, including task priority like A, B, C). Here is my current query:

#+BEGIN_QUERY
{
:query [
    :find (pull ?p [:block/name]) 
    :where 
        [?p :block/name]
        (not-join [?p]
            [?b :block/page ?p] 
            (not [?b :block/path-refs [:block/name "query-tag"]])
            )

    ]
}                           
#+END_QUERY

I have searched forum, discord and datomic docs but couldn’t identify the problem. any insights or suggestions? I would greatly appreciate your assistance. Thank you!
Relevant topic: does every value for a given entity attribute exactly match a given set? - #5 by dustingetz - General - Datomic Developers Datalog: does every value for a given entity attribute exactly match a given set? - #5 by dustingetz - General - Datomic Developers [/s]

Welcome.

  • Your current query is very broad.
    • The nested nots filter very little.
  • Your scenario sounds simple.
    • The size of the right query will probably remain around the same.
    • However, your description is particularly hard to follow.
      • Please rephrase it in a less abstract form, like providing an example:
        • in simple English
        • without terminology

Thanks for your response! I have rephrased the description and included an additional example. Let me know if there are any other unclear parts.

Something like this:

#+BEGIN_QUERY
{
:query [
    :find (pull ?p [:block/name]) ; the name of pages
    :where                        ; that
        [?b :block/page ?p]                        ; contain some block
        [?b :block/refs [:block/name "query-tag"]] ; that references #query-tag
        (not                                       ; and do not
            [?other :block/page ?p]                              ; contain any other block
            (not [?other :block/refs [:block/name "query-tag"]]) ; that does not reference #query-tag
        )
    ]
}
#+END_QUERY
3 Likes