datahike

silian 2025-09-01T04:17:45.858969Z

In docs example,

(transact conn [{:db/id  -1
                 :name   "Oleg"
                 :_friend 296}])
;; equivalent to
(transact conn [[:db/add  -1 :name   "Oleg"]
                [:db/add 296 :friend -1]])
This would mean db registers that Ivan, 296, considers Oleg a friend (`[:db/add 296 :friend -1]`) but not necessarily that Oleg considers Ivan a friend. 🥲 Would that be correct interpretation of assertions of the db?

2025-09-02T14:40:18.089979Z

the :_friend part won't really appear in the schema; it's not a real attribute. it's implicit, since every :db.type/ref attribute can be considered both forwards (by its actual :db/ident, eg. :friend) and backwards (with the leading underscore, :_friend).

2025-09-02T14:43:59.856529Z

as to whether it's worth specifying refs even when you'd prefer to avoid schema, I think it's absolutely worth the effort. compare with DataScript, which is in-memory and so doesn't need to care about value types: it still supports :db.type/ref! knowing the number is a ref enables a lot of powerful things, such as transacting nested maps. (transact conn [{:some/value "foo", :something/nested {:nested/value 12}}]) will create two entities, something like this:

300 :some/value       "foo"
300 :something/nested 301
301 :nested/value     12

2025-09-01T14:46:07.174989Z

all refs are indexed in both directions, but two-way relationships are sometimes useful anyway. by convention the reverse relationship is spelled :_friend. note that even if the forward relationship is :cardinality/one, the reverse is always :cardinality/many, because there's no limit to how many other entities might point their single at a given entity.

2025-09-01T14:47:41.542289Z

it's a more natural fit for "follows" relationships than symmetrical ones like friendship.

silian 2025-09-01T19:34:25.947189Z

If I understand, (transact conn [[:db/add -1 :name "Oleg"][:db/add 296 :friend -1]]) produces in EAV form something like:

301 :name    "Oleg"
301 :friend   296
296 :_friend  301
I am using :schema-flexibility :read and so, during the tx above, somehow the following schema is inferred and transacted as something like:
[{:db/ident       :friend
  :db/valueType   :db.type/ref
  :db/index       true
  :db/cardinality :db.cardinality/one}

 {:db/ident       :_friend
  :db/valueType   :db.type/ref
  :db/index       true
  :db/cardinality :db.cardinality/many}]
Is that about right?

silian 2025-09-01T20:45:26.715179Z

Because I am extremely lazy (and work alone) I am trying to understand how to avoid defining schema as much as possible while still producing the right "relationships" needed for EAV. Generally, I dislike using db.type/ref but I guess this is the only way db knows it is looking at a reference rather than a primitive Numeric?

silian 2025-09-01T04:26:05.905269Z

(I am trying to understand if the assertion creates a "two-way" [or "reciprocal"] relationship or just a one-directional pointer.)