1

I have some doubts about datomic.api/tempid fn that provides entity id.

It produces some long value, not UUID String and long is 64 bit which makes me think about it's uniqueness after some point I might reach long's limit. It would be harder with UUID instead.

When I write some code like this, I ask myself "Does this reach the entity id limit and cause a problem when adding new entities?"

@(d/transact
   conn
   [{:db/id   (d/tempid :db.part/user)
     :city/district "BEYKOZ"}])
Ertuğrul Çetin
  • 5,131
  • 5
  • 37
  • 76

1 Answers1

8

As the name suggests, tempid only provides a temporary identifier; these are to be used within the context of a single transaction. So you're not going to run out of IDs unless you exceed 2^64 new records within a single transaction—and that kind of transaction would be way too large to run anyway.

The primary purpose of tempids is to allow us to reference newly-created entities in multiple places within a transaction.

In fact, the map-based transaction format is a shorthand for the vector-based format; if we want to create a city with a couple attributes, internally, Datomic is doing something more like:

@(d/transact
   conn
   (let [city-id (d/tempid :db.part/user)]
     [[:db/add city-id :city/district "BEYKOZ"]
      [:db/add city-id :city/population 220364]]))

...which is only possible with some kind of shared identifier, but we don't know the permanent, insert ID until we've round-tripped from the database.

Tempids also allow us a way to find these permanent IDs via the return value of transact, by looking into a map of temp IDs to permanent IDs. e.g.

(let [tempid (d/tempid :db.part/user)
      tx     [{:db/id tempid, :city/district "BEYKOZ"}]
      result @(d/transact conn tx)]
  (d/resolve-tempid (:db-after result) (:tempids result) tempid))

It's also worth noting that as of Datomic 0.9.5530, you don't need to add tempids manually to new records (simply leave the :db/id out of the map), and you can also use strings as tempids. So, for example, we could rewrite the city transaction as:

@(d/transact
   conn
   [[:db/add "beykoz" :city/district "BEYKOZ"]
    [:db/add "beykoz" :city/population 220364]])
camdez
  • 1,614
  • 1
  • 18
  • 18
  • If I add more than 2^64 :city/district "some-val" in different transactions over time, still I'm going to exceed the entityId right? Because I will have more than 2^64 :city/district entries and DB won't be able find new long value? – Ertuğrul Çetin Mar 17 '17 at 16:52
  • Based on [this mailing list discussion](https://groups.google.com/forum/#!topic/datomic/s0u3vjb0GG4), I think you're approximately right. It sounds like the maximum number of entities is actually about 2^42. But keep in mind that those are just entity limits, and you can have a lot of *facts* about those entities before you start hitting limits there. – camdez Mar 17 '17 at 17:12
  • 3
    That's a lot of districts! If you have 2^64 unique :city/districts, your total dataset is likely [zettabyte-sized](https://en.wikipedia.org/wiki/Zetta-), giving you maybe the largest single dataset on the planet, and a nontrivial fraction of [all data on the planet](http://www.computerweekly.com/news/2240217788/Data-set-to-grow-10-fold-by-2020-as-internet-of-things-takes-off). This is not going to be a good fit for Datomic. Whatever database you choose, make sure to keep a close eye on your [storage costs](http://gizmodo.com/5557676/how-much-money-would-a-yottabyte-hard-drive-cost). – Stuart Dabbs Halloway Mar 22 '17 at 18:07
  • @StuartDabbsHalloway Got it, thank you for the explanation! – Ertuğrul Çetin Mar 28 '17 at 14:56