Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Cloud by

I'm wanting to use a lookup ref instead of an entity id (:db-id) when specifying the value for a tuple of attributes where one of the attributes is of type :db.type/ref. Is this possible? I've looked over the Datomic Cloud grammar on transactions and I don't see how to specify a tuple value at all (maybe I'm missing something). I've tried what I thought would be the obvious way to do it and this doesn't work. Here's what I have...

Truncated schema:

{:db/ident       :molecule/legacy-id
 :db/unique      :db.unique/identity
 :db/valueType   :db.type/long
 :db/cardinality :db.cardinality/one
 :db/doc         "The Molecule/Complex id from the ProcessDB Oracle database."}
{:db/ident       :molecule-part/number
 :db/valueType   :db.type/long
 :db/cardinality :db.cardinality/one
 :db/doc         "The number of molecules for this molecule. The entity with this attribute may be reused and is
 not unique for a particular complex so do not change this number. Instead, check for another existing entity
 or create one."}
{:db/ident       :molecule-part/molecule
 :db/valueType   :db.type/ref
 :db/cardinality :db.cardinality/one
 :db/doc         "The molecule this part refers to. The entity with this attribute may be reused and is
 not unique for a particular complex."}
{:db/ident       :molecule-part/number+molecule
 :db/unique      :db.unique/identity
 :db/valueType   :db.type/tuple
 :db/tupleAttrs  [:molecule-part/number :molecule-part/molecule]
 :db/cardinality :db.cardinality/one
 :db/doc         "The number and molecule that collectively form the unique identity of this entity."}

Then I try to add a molecule part using

(d/transact (db/get-connection) {:tx-data [{:molecule-part/molecule [:molecule/legacy-id 717] :molecule-part/number 1 :molecule-part/number+molecule [1 [:molecule/legacy-id 717]]}]})

And get the following error

:db.error/invalid-tuple-value Invalid tuple value

If I replace "[:molecule/legacy-id 717]" with the entity id (:db/id) for that molecule then it works. But I don't want to use the entity id... I want to use the lookup ref, because what I have is the :molecule/legacy-id. I don't want to have to do a query to resolve this before doing a transaction to add the :molecule-part.

1 Answer

+1 vote
selected by
Best answer

You don't have to specify the composite key's value usually, just its constituent attributes, because those imply the composite key and Datomic will add it to the resulting transaction automatically.

So this should be sufficient:

 {:tx-data [{:molecule-part/molecule [:molecule/legacy-id 717],
             :molecule-part/number 1}]})

That being said, if you want to update an existing entity, you do have to provide an attribute in a transaction, which is a :db.unique/identity, so you would need the :molecule-part/number+molecule [1 [:molecule/legacy-id 717]] map entry, which doesn't work.

As discussed here:
you would need to create a custom transaction function, which resolves the lookup refs used in your unique tuple attr and return entity IDs instead.

Indeed, I want to update an existing entity that has :db.unique/identity on the tuple attribute. I found that providing the individual attributes will not resolve the entity but simply complain that the values are not unique. That's why I tried to use a lookup-ref within the tuple. Thanks for the answer. I could use a db fn.