This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # bangalore-clj (3)
- # beginners (103)
- # boot (13)
- # cider (16)
- # cljs-dev (192)
- # cljsrn (44)
- # clojure (147)
- # clojure-dev (1)
- # clojure-italy (79)
- # clojure-norway (1)
- # clojure-russia (9)
- # clojure-spec (4)
- # clojure-uk (34)
- # clojurescript (65)
- # core-async (1)
- # core-logic (2)
- # core-typed (5)
- # cursive (1)
- # datascript (9)
- # datomic (26)
- # emacs (8)
- # garden (1)
- # hoplon (11)
- # humor (1)
- # jobs (1)
- # jobs-discuss (8)
- # jobs-rus (3)
- # leiningen (1)
- # luminus (1)
- # lumo (1)
- # mount (6)
- # off-topic (16)
- # om (10)
- # om-next (1)
- # onyx (10)
- # parinfer (10)
- # pedestal (25)
- # re-frame (27)
- # reagent (3)
- # rum (47)
- # uncomplicate (1)
- # unrepl (34)
- # untangled (120)
- # vim (58)
> the cost of an error would be eternally corrupt data, given the write-only nature of datomic
@matan @hmaurer Not true in my experience. That would be the case if you relied on past versions of your database in online code, which you don't want to do anyway in the vast majority of cases, for even other reasons than recovering from data corruption (schema evolutions, migrations, offline imports etc.) - it's a common misunderstanding of beginners (myself included) to think that they're going to use stuff like
db.asOf() extensively in online code, but it usually turns out it's not very viable. Then the situation is the same as mutable DBs such as RDBMS, except that when data corruption does occur, you have all the historical and speculative features of Datomic to track down how it happened and reproduce it, which gives you an advantage in solving the problem.
@hmaurer @U08715BSS I definitely need to write a blog post about that, but think about what happens when you need to make a data migration and / or expand your schema; you won't be able to consume this changes in an asOf db. Features giving users access to several versions of an object (à la google docs for instance) should generally not be implemented using asOf(), but by reifying versions into version entities - keep asOf() for auditing and debugging.
@val_waeselynck True… Would you copy over to the “version” entity all the attributes of the entity? I guess this would be a good use-case for a transaction function
@val_waeselynck Can you expand on why using
(:as-of db) didn't turn out to be viable? we're not using yet, but have thought of doing so
new to datomic and having trouble figuring out how to model something in it, would love some insight:
a user (unique identity on email, let’s say) can be a part of multiple organizations. within each organization, a user has a role, which can be an enum of a few different options.
I started by trying to model this with a schema of 1) an organization having
ref to a user which is
:cardinality/many 2) each user is associated with an organization via that ref. unfortunately, I couldn’t figure out a way to slide a
:user/role or similar property into the schema easily considering that for each organization that a user is a part of, they might have a different role.
the second thing I thought of doing was creating a different user for every association with an organization. so user A can be a part of organization A with role ABC, and user A can also be a part of organization B with role XYZ, but there’s a different record for each user within the db for their participation in each organization. that feels slightly heavyweight, though, because I’d have a bunch of duplicate user records laying around.
what I’m struggling with is that it seems in datomic there’s not an easy way to say “this thing is related to this other thing, and the relation itself has a property”.
if anyone has any insight about how I might go about this, would love some input. I’m new to datomic, so apologies if I’m missing something obvious.
thanks in advance for any help!
:user/memberships many ref, :membership/org one ref, :membership/roles many enum if you often need to go from user direct to org or vice versa, you can also model than directly
:user/orgs many ref, but you’ll have to take care of keeping both paths aligned, or at least make your code resilient to misaligned collections
in SQL this would have been done with a join table, but in Datomic, we simply reify the relationship as an entity with its own name
pretty straightforward. just such a different way of modeling data/relationships, have to relearn how to use a database 😝
@mss this is a common situation with tuple stores (including RDF stores and graph stores). There are two generic ways to do it: with an additional column in the tuple, or via explicit reification. In the Datomic case, explicit reification is as robert described: you introduce a new entity with new labeled links. Datomic has a
tx field in its
e a v tuples, so in some cases it’s appropriate to use that as the reified entity.
For example, there are two ways to represent a person joining an organization on a given date: either
[x :foo/join y] [y :foo/org :myorg] [y :foo/joinedOn date], or
[x :foo/joinedOrg :myorg tx] [tx :db/txInstant date]
In your case you probably wouldn’t use metadata about the transaction to describe a role, but you could, and it might be appropriate in other situations — particularly those in which you’re trying to model some information about how the data was generated or recorded.
Other tuple stores like AllegroGraph have five fields, not four — AG lets you make assertions about an tuple’s ID, and also use a ‘graph’ field for any purpose you like.
I hear that, def makes a lot of sense when the additional component of the tuple is time based or otherwise representable by the transaction metadata itself
I quote: > The :db.fn/cas (compare-and-swap) function takes four arguments: an entity id, an attribute, an old value, and a new value. The attribute must be :db.cardinality/one. If the entity has the old value for attribute, then the new value will be asserted. Otherwise, the transaction will abort and throw an exception.
Does that mean that the whole transaction will abort? (not just the operation containing the cas?)
and does the position of the
:db.fn/cas vector in the transaction (e.g. if the transaction has multiple operations) matter?
Actually nevermind, my question makes no sense. Of course it has to abort the whole transaction, since it’s a “transaction”. It couldn’t reject just the
:db.fn/cas operation and apply the others, as it would break the atomicity guarantee.