Fork me on GitHub
#datomic
<
2016-07-28
>
zentrope02:07:49

Is there a way to query such that you pass in a vector for one of the terms? (q '[:find ?e :in $ ?ns :where [?e :foo/bar ?ns]] db [“a” “b” “c”])

zentrope02:07:53

That sort of thing?

zentrope02:07:22

Or do you have to call it X times, or use a rule?

yonatanel12:07:23

When :finding multiple aggregations on different entity attributes, how can I avoid ignoring entities that are missing one of the attributes? In the following query, entities 2 and 3 are not participating in the aggregation because of unification. (q '[:find ?e (min ?a) (max ?b) :where [?e :a ?a] [?e :b ?b]] [[1 :a 400] [1 :b 100] [2 :a 200] [3 :b 500]]) => [[1 400 100]]

dominicm13:07:05

@yonatanel: two answers to that: Easy one is: http://docs.datomic.com/query.html#sec-5-12-1 The long one is: don't. Query is just for saying what the base rules are for an entity, and how to return that entity. Then you lazily/using pull syntax, get the attributes of that entity.

yonatanel13:07:44

@dominicm: Currently I've separated the queries, one for min and one for max, and merged the results. How would you have done it?

dominicm13:07:52

derp, didn't see the min/max. Your approach is good, there's no need to try and cram as much into a single query as the db is local.

yonatanel13:07:08

Thanks. Though it's not cramming stuff into a query, but declaring what you want and expecting the library to worry about the rest. Splitting queries because of implementation details is just the same as cramming everything into one because of remote connections.

dominicm14:07:44

Hmm, not sure about it being an implementation detail. When you make a query, you say you're looking for an entity with all these attributes.

dominicm14:07:34

You could implement your own aggregate if you're really interesting in pursuing this. Using http://docs.datomic.com/query.html#sec-5-12-1 get-else, you can return nil if the value isn't there. max would first filter out nil values, before applying max like normal.

yonatanel14:07:36

I'm not sure that's what I'd like to see, but Cascalog for example has optional binding with '!' instead of '?'

dominicm14:07:01

Actually, max might be smart enough to handle nils already... Yeah, try get-else

yonatanel14:07:03

I wonder if max/min are using indexes and whether get-else interferes with it

zentrope16:07:35

@bkamphaus: Yes, that’s it. My first attempt didn’t work because I forgot the “…” on the pull function.

zentrope17:07:03

When you’re associating entities, do you just :thing/list [3424234, 32423432, 45634342] (those being :db/ids), or do you structure them with [:db/id 43534534]?

zentrope17:07:29

Huh. I can’t see an example in the docs. I suppose the error messages will teach me. ;)

zentrope17:07:32

@codonnell: I think it worked using a vector of entity ids.

zentrope17:07:01

I suspect [:db/id <some-existing-id>] would also work.

Chris O’Donnell17:07:17

I'm trying to learn this stuff myself, as well. What does your transaction look like, if you don't mind? I tend to use lookup refs, which sit as maps in my transactions.

Chris O’Donnell17:07:02

For example, [[:receipt/id 42 :db/id (d/tempid :db.part/user) :receipt/customer {:customer/id 15}]]

zentrope17:07:12

Ah, I see in the second example in the “Nested maps in transactions” shows that you can just use a vector of IDs.

Chris O’Donnell17:07:28

"When a transaction adds an attribute of reference type to an entity, it must specify an entity id as the attribute's value." Ok, so attributes of ref type are just entity ids. Makes sense how your vector of db/ids works.

zentrope17:07:00

My particular case is something like “tags” and “notes”. You have tags, and you have notes, but for this given note, you need pointers to a list of tags. (Assume tags are more interesting than just a keyword or something — the analogy isn’t perfect.)

zentrope17:07:11

So, I already know the tag ids.

zentrope17:07:59

The struggle is a DB function that knows how to update the “note” such that it retracts or adds appropriate tags, depending on the value of the DB at the time of the transaction. (So a nice history is maintained.)

zentrope17:07:27

The other option is to retract all the tags, then assert all new tags (which may or may not have changed).

zentrope17:07:07

It’s the one use case I wish datomic had some help with.

zentrope17:07:12

A “set” type.

zentrope17:07:35

Or set cardinality, or something like that.

Chris O’Donnell17:07:07

I don't think your :thing/list has any particular order; it just associates the :thing entity with each of the ids it is passed

Chris O’Donnell17:07:38

the vector notation is just a convenient syntax for adding multiple associations at once

zentrope17:07:02

Yes, but of :thing/list already exists and I give it a subset of what it used to be, it’ll just add the two sets together. It won’t retract anything.

zentrope17:07:07

One option is to make a TX function that queries for the old values, does some comparisons (clojure.data/diff is nice for that), then you build the transaction that way.

zentrope17:07:58

@marshall: Yes, I’ve seen that and a lot of other discussions. Been down this road before.

zentrope18:07:41

Interesting. If you do something like :thing/list [{:a/b id :x/y [id1 id2]} {:db/id id6 :x/y [id9 id10]}] then I don’t see how to retract one of those objects. There’s no db/id I can see for stuff in thing/list. Hm.

zentrope19:07:10

If you have a database transaction and decide no changes need to be made, do you return an empty vector?

marshall20:07:34

@zentrope: yes, an empty transaction will create an entry in the log, but not affect any other datoms

zentrope23:07:57

Is there a discussion of not and not-join somewhere other than in the docs?