Hello all, I struggle with a query. I have a schema with a many cardinality. I want to find some entities in that many relationship. The query below is a simplified example: There is a “P1” entity with 3 followers (:follows) and I want to find only 2 of those 3 followers. My understanding is I can differentiate using [?p1 :follows ?p2] and [?p1 :follows ?p3]But as soon as I add the clause [?p1 :follows ?p3], the result set is empty.
(def schema {:follows {:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many}
:name {:db/valueType :db.type/string
:db/unique :db.unique/identity}})
(def conn (d/get-conn "~/tmp/datalevin/test" schema))
(d/transact! conn
[{:db/id 1 :name "P1", :follows [{:db/id 2} {:db/id 3} {:db/id 4}]}
{:db/id 2 :name "P2" :follows [{:db/id 10}]}
{:db/id 3 :name "P3"}
{:db/id 4 :name "P4"}
{:db/id 10 :name "P10"}])
(d/q '[:find
?p1 ?p2 ?p3
:where
[?p1 :name "P1"]
[?p1 :follows ?p2]
[?p2 :name "P2"]
[?p1 :follows ?p3]
[?p3 :name "P3"]]
(d/db conn))
Can someone explain what I’m missing ? Thank youYour query says give me entities which satisfy all those requirement. But none of them can satisfy all those requirements simultaneously. I’d write it like this:
(d/q '[:find (pull ?f [:name])
:where
[?p1 :name "P1"]
[?p1 :follows ?f]
(or
[?f :name "P2"]
[?f :name "P3"])]
(d/db conn))
or like this if you don’t want to use pull and want the person they follow in the result set:
(d/q '[:find ?p ?n
:where
[?p :name "P1"]
[?p :follows ?f]
(or
[?f :name "P2"]
[?f :name "P3"])
[?f :name ?n]]
(d/db conn))Thank you. That works . I still need to figure out why the p1, p2 and p3 in my example are not considered different entities, each one satisfying the requirements.
Because each entity must satisfy both those requirement: Give me followers that have name P2.
[?p1 :follows ?p2]
[?p2 :name "P2"]
Who also have name P3.
[?p1 :follows ?p3]
[?p3 :name "P3"]
There are no followers that have name P2 and P3. So you get no results.
?p3 and ?p2 are not bound to specific entities, all entities must satisfy both those patterns.
So what’s happening is:
[?p1 :follows ?p2]
[?p2 :name "P2"]
Matches on:
{:db/id 2 :name "P2" :follows [{:db/id 10}]}
But it does not satisfy:
[?p1 :follows ?p3]
[?p3 :name "P3"]
So gets discarded. The same happens with:
{:db/id 3 :name "P3"}
Hope that makes more sense.Thanks for the extra explanation. I misunderstood that (somewhere in the matching/join process) ?p2 and ?p3 would be bound to different entities (selected from the list of followers) and would satisfy the condition. It becomes clear now
It can and it can’t the way I think about it is the result has to satisfy all your where clauses. So this would be an example where p1 and p2 are different entities. Say you want to find someone who is followed by someone who is also followed:
(d/q '[:find ?n
:where
[?p1 :follows ?p2]
[?p2 :follows ?p3]
[?p3 :name ?n]]
(d/db conn))
=>
#{["P10"]}
The last example is easier to understand.
Really? The first query requires that ?p2 and ?p3 be unified even though the attribute is cardinality-multiple? The "I'd write it like this" does not accomplish the same thing. The OP query wanted two distinct followers. The "I'd write it like this" tolerates a single follower.
Good point about the single follower.
So you’re right the OPs query does work with cardinality many in vanilla datascript.
OK, sounds like we should file this as a bug
Fixed
Hi everyone, I'm getting this error while trying to use datalelvin as a kvs, any pointers on how to get it working? Thanks nixos, java 19.0, clj 1.11
What :jvm-opts are you passing? The issue might be related to needing to pass:
“--add-opens=java.base/java.nio=ALL-UNNAMED”
“--add-opens=java.base/sun.nio.ch=ALL-UNNAMED”
or not, but worth checking.
It worked. thanks. I literally just stumbled across https://github.com/lmdbjava/lmdbjava/issues/182#issuecomment-917838805 right as I saw your comment 😂