Hello everyone, I have two entities, user and address, I was trying to use tuples to restrict a user to have only addresses with different types, but when I transact one user with address it doesn't put the address type too ":user/id+addrtype [#uuid "c8335aeb-686f-438b-bbb7-06691ac81c69" nil]". This is my tuple:`{:db/ident :user/id+addrtype :db/tupleAttrs [:user/id :address/type]}` . Is that correct or is there any alternative I can use for this problem?
What is the tx-data and full schema @cbluan?
It works when I use :address/type along with :user/id and the same data nested
I can't help unless I see the schema and tx-data
Sorry, I misclicked, this is the schema:
{:db/id #db/id [:db.part/db]
:db/ident :address/type
:db/valueType :db.type/string
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :address/street
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :user/id
:db/valueType :db.type/uuid
:db/unique :db.unique/identity
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :user/name
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :user/address
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many
:db.install/_attribute :db.part/db}
{:db/ident :user/userid+type
:db/valueType :db.type/tuple
:db/tupleAttrs [:user/id :address/type]
:db/cardinality :db.cardinality/one
:db/unique :db.unique/identity
:db.install/_attribute :db.part/db}
And the tx:
{:user/id #uuid "c8335aeb-686f-438b-bbb7-06691ac81c69"
:address/type "Home" ;; it it works when I add it here
:user/name "Chris"
:user/address {:db/id (d/tempid :db.part/user)
:address/type "Home"
:address/street "St. 222"}}
Validate an experiment for me:
I really do want you to use "Foo"
here for the address type
first transact:
{:db/id (d/tempid :db.part/user)
:address/type "Foo"
:address/street "St. 222"}
Then, in a second transaction, transact:
{:address/type "Foo"
:address/street "St. 123"}
Then:
(d/pull a-fresh-db '[*] [:address/type "foo"])
What do you get back?I used "Foo" instead, using only these two transactions I get: {:db/id 17592186045418, :address/type "Foo", :address/street "St. 123", :user/userid+type [nil "Foo"]}
So it appears that in your schema :address/type
is unique like :user/id
, and therefore, whenever a second address with {:address/type "Home", :address/street "Route 66"}
is added to the system it would overwrite the first user's address.
Your users might find this problematic 🙂
The reason the tuple "Works" when you attach it to the user is because you have what is known as a "composite tuple", which can only read attributes from the same entity, not nested ones.
How many :address/type
's you expect to have in your application?
If the answer is "A small number" you might benefit from creating some new attributes instead of an address entity.
Example:
{:user/id #uuid "123..."
:user/name "Chris"
:address.home/street "St. 222"
:address.billing/street "st. 123"
:address.work/street "Route 66"}
Schema would be something like:
{:db/id #db/id [:db.part/db]
:db/ident :address.home/street
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :address.work/street
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :address.billing/street
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
Then, a user can only have 1 address of each "type"
I was trying to to this composite tuple, but I didn't know it doesn't work on nested entities 🙂 And I also was trying to model it to support another entity like Company to have an address, so I would just ref to it. I will think about this solution, thank you 🙂 .
FWIW @cbluan, companies can use those same attributes:
{:db/id #db/id [:db.part/db]
:db/ident :address.mailing/street
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :favorite/color
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :company/name
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :company/employees
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many
:db.install/_attribute :db.part/db}
Then:
{:company/name "Acme
:favorite/color "Blue"
:address.mailing/street "Route 66"
:address.billing/street "123 Nowhere St."
:company/employees [
{:user/id #uuid "123..."
:user/name "Chris"
:favorite/color "Green"
:address.home/street "St. 222"
:address.billing/street "st. 123"
:address.work/street "Route 66"}
]}
Don't think in