is datahike.api/entity
supposed to return more than just #:db{:id 229}
? I'd like to see all the attributes for a given entity, but it only ever returns the :db/id
here's my short reproduction:
(d/transact db/conn [{:db/ident :item/id
:db/valueType :db.type/keyword
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :item/description
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:item/id :foo
:item/description "bar"}])
(d/entity @db/conn [:item/id :foo])
;;=> #:db{:id 232}
I would expect to see :item/id
and :item/description
, I think. But I want to make sure I'm using it correctly.
I'm happy to help poke at it if need be
@datran it looks like a hashmap but it's not
(type (d/entity @conn [:name "Alice"])) ;;=> datahike.impl.entity.Entity
(into {} (d/entity @conn [:name "Alice"])) ;;=> {:age 20, :name "Alice"}
Check the doc for d/entity
🙂Thanks! That works perfectly. So, I have to realize the results every time?
Depends on what you want out of it! You can also just use it like a hashmap
just the .toString
won't show you what you're looking for
(:age (d/entity @conn [:name "Alice"])) ;;=> 20
ok, now it's all coming together. That's what you get for coding too late
hehehe I'm right there with ya
I guess while we're here, how do you model many-to-many joins? In SQL I would create a join table, do I have to create a join entity?
I've got two entities, a warehouse and a widget. The widget has a :widget/type and :widget/description. The warehouse has a lot of properties. I want to create a relationship between the two that can express the quantity of widgets a warehouse has.
In SQL, I would have two tables, widgets and warehouse, and I would create a join table to bridge the two and track the quantity - warehouse_widgets(warehouse_id, widget_id, widget_quantity)
. How do I do that in datahike?
I've got this schema:
(d/transact db/conn [{:db/ident :warehouse/id
:db/valueType :db.type/keyword
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :widget/id
:db/valueType :db.type/keyword
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :widget/description
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
])
And I've tried this:
{:db/ident :widget/count
:db/valueType :db.type/long
:db/cardinality :db.cardinality/many}
Hold on, here's a more clear repl history:
(d/transact db/conn [{:db/ident :warehouse/id
:db/valueType :db.type/keyword
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :widget/id
:db/valueType :db.type/keyword
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :widget/description
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :widget/warehouse
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many}
{:db/ident :widget/count
:db/valueType :db.type/long
:db/cardinality :db.cardinality/many}
])
(d/transact db/conn [{:warehouse/id :foo}
{:warehouse/id :bar}
{:widget/warehouse [:warehouse/id :foo]
:widget/count 3
:widget/id :x}
{:widget/warehouse [:warehouse/id :bar]
:widget/count 5
:widget/id :x}])
(d/q {:query '{:find [?e ?c ?w-id]
:where [[?e :widget/id :x]
[?e :widget/count ?c]
[?e :widget/warehouse ?w]
[?w :warehouse/id ?w-id]]}
:args [@db/conn]})
#{[229 3 :foo] [229 5 :bar] [229 3 :bar] [229 5 :foo]}
I want that to return #{[229 3 :foo] [229 5 :bar]}
, but it looks like each count is applied to each warehouse
Hmm okay I see what you're trying to do. So -- personally I wouldn't store the count. I use an aggregation to get the count. Let me see if I can work up the example
(d/transact conn [{:db/ident :container/name
:db/valueType :db.type/string
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one}
{:db/ident :container/stuff
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many}
{:db/ident :thing/name
:db/valueType :db.type/string
:db/unique :db.unique/value
:db/cardinality :db.cardinality/one}])
(d/transact conn [{:container/name "a"}
{:container/name "b"}])
(d/transact conn [{:thing/name "thing1"}
{:thing/name "thing2"}
{:thing/name "thing3"}])
(d/transact conn [{:container/name "a"
:container/stuff [[:thing/name "thing3"]]}
{:container/name "b"
:container/stuff [[:thing/name "thing1"]
[:thing/name "thing2"]]}])
(d/q '[:find (count ?thing) .
:where
[?e :container/name "a"]
[?e :container/stuff ?thing]]
@conn) ;;=> 1
(d/q '[:find (count ?thing) .
:where
[?e :container/name "b"]
[?e :container/stuff ?thing]]
@conn) ;;=> 2
this site covers it in pretty good detail: http://www.learndatalogtoday.org/chapter/7
That's good to know, I didn't know about the aggregation functions. However, when I play with your example I get a weird result when I try this:
(d/transact db/conn [{:container/name "a"
:container/stuff [[:thing/name "thing3"]]}
{:container/name "b"
:container/stuff [[:thing/name "thing1"]
[:thing/name "thing1"] ; note that I've repeated "thing1"
[:thing/name "thing2"]]}])
(d/q '[:find (count ?thing) .
:where
[?e :container/name "b"]
[?e :container/stuff ?thing]]
@db/conn) ;;=> 2 (I would expect 3)
since "thing1" is a unique identity, it will not get added twice. That transaction probably should've thrown an exception though :thinking_face: