tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.5k stars 309 forks source link

filter whole entities with d/filter #63

Closed ThomasDeutsch closed 9 years ago

ThomasDeutsch commented 9 years ago

I open this issue since i can not find a documentation/test on how to accomplish this.

How can i filter an entity based on one attribute value?

For example, i would like to set a filter that will return entities where :name=="Ivan"

[{:db/id 1
 :name  "Petr"
 :email "petya@spb.ru"
 :aka   ["I" "Great"]
 :password "<SECRET>"}
 {:db/id 2
  :name  "Ivan"
  :aka   ["Terrible" "IV"]
  :password "<PROTECTED>"}]

(defn only-evans [udb datom] .....)

(d/filter db only-evans) 

will only return [[{:db/id 1 :name "Petr" :email "petya@spb.ru" :aka ["I" "Great"] :password ""}]

tonsky commented 9 years ago

What is your source? Db? Datoms? Entities?

(d/q '[:find [?e ...]
       :in $ ?n
       :where [?e :name n]]
      db "Ivan")
;; => [1, 2, 3]

(filter (fn [datom]
          (and (= (.-a datom) :name)
               (= (.-v datom) "Ivan")))
        datoms)
;; => [#datascript.core/Datom{:e 1, :a :name, :v "Ivan"}, ...]

(filter (fn [entity]
          (= (:name entity) "Ivan"))
        entities)
;; => [{:db/id 1, :name "Ivan"}, {:db/id 2, :name "Ivan"}, ...]
tonsky commented 9 years ago

Oh, you’re asking about datascript/filter. Try this:

(d/filter db
  (fn [db datom]
    (and (= (.-a datom) :name)
         (= (.-v datom) "Ivan"))))

This will only keep datoms which are about :name ([* :name *]), so essentially querying such db will get you just

{:db/id 2, :name "Ivan"}

without any other properties of entity.

You probably want to keep any attributes of entity if that entity has a :name attribute equal to "Ivan". Then

(d/filter db
  (fn [db datom]
    (let [eid    (.-e datom)
          entity (d/entity db eid)]
      (= "Ivan" (:name entity)))))
ThomasDeutsch commented 9 years ago

I am rewriting the datascript todo app. For the filtering, i would like to pass a filtered db to my todo-list ( like you described in the video ).

The last example is just what i needed. Thanks!