How can I find whether a many cardinality attribute in Datascript contains an element?

253 Views Asked by At

I have a Datascript db that's like this:

{:block/id {:db/unique :db.unique/identity}
 :block/children {:db/cardinality :db.cardinality/many}
}

:block/children contains :block/id of other blocks

I've been trying to write a query to find which block has another block as its child.

Here's an example of what I've tried:

(ds/q '[:find ?parent-ds-id
        :where
        [1100 :block/id ?block-id]
        [?parent-ds-id :block/children ?block-id]]
      @conn)

I just get the empty set back in return. How am I supposed to dress up ?block-id so that I get back the entity ID of the block who has ?block-id as one of its children? (Every block only ever has one parent)

1

There are 1 best solutions below

0
On

This problem could be related to the data you are using. This is an working example of what you are after:

(let [schema {:block/id {:db/unique :db.unique/identity}                                                                                                                                       
              :block/children {:db/valueType :db.type/ref                                                                                                                                      
                               :db/cardinality :db.cardinality/many}}
      conn (d/create-conn schema)                                                                                                                                                              
      idify (fn [id] (* 100 id)) ; just fake some id
      block (fn [id] {:db/id (idify id) :block/id id})                    
      rel (fn [parent-id child-id] {:db/id (idify parent-id) :block/children (idify child-id)})]
  (d/transact! conn [(block 1)               
                     (block 2)               
                     (block 3)
                     (rel 1 2)
                     (rel 1 3)])  
  (d/q                       
   '[:find ?parent-id                
     :in $ ?child-id           
     :where                                   
     [?child :block/id ?child-id] 
     [?parent :block/children ?child]
     [?parent :block/id ?parent-id]]
   @conn                                  
   2))                                                 
; → #{[1]}

Although your block-ids are most likely already the unique ids you want to use for your entities, this uses different entity ids just to make it clear, how the data can be combined.

This query establishes:

  • we want the child entity with the block id given (2 via parameters)
  • we want the parent entity, that references the child entity
  • we want the block id of the parent entity