Reputation: 4976
Let's say I have a list of movies and I can get them all this way:
[:find ?year ?title ?rating
:where
[?Movie :movie/year ?year ]
[?Movie :movie/year ?title ]
[?Movie :movie/year ?rating]]
How can I further restrict this to get only the movie with the highest rating? I feel like I want something like...
[:find ?year ?title ?rating
:where
[?Movie :movie/year ?year ]
[?Movie :movie/year ?title ]
[?Movie :movie/year ?rating]
[(= ?rating (max ?rating) ]]
But obviously that won't do what I want =) Tips?
Upvotes: 2
Views: 685
Reputation: 1665
It's OK to do this sort of thing with two queries in Datomic. Having peers cache databases locally means the pressure to get as much done in one query is relieved a bit.
[:find (max ?year) .
:where [?m :movie/year ?year]]
Followed by:
[:find ?maxyear ?title ?rating
:in $ ?maxyear
:where [?m :movie/year ?maxyear]
[?m :movie/title ?title]
[?m :movie/rating ?rating]]
Is ok. The chained queries in Clojure could look like:
(let [db (d/db conn)]
(->>
(d/q '[:find (max ?year) .
:where [?m :movie/year ?year]]
db)
(d/q '[:find ?maxyear ?title ?rating
:in $ ?maxyear
:where [?m :movie/year ?maxyear]
[?m :movie/title ?title]
[?m :movie/rating ?rating]]
db)))
Notice we only get the db value from the connection once in the let binding. It is possible to use collection returning functions to get the result you've mentioned with the right constraints, but this may not behave how you'd expect - as with this example that gets the latest Beatles release:
(d/q '[:find (max ?tuple)
:where [?e :artist/name "The Beatles"]
[?a :release/artists ?e]
[?a :release/year ?y]
[?a :release/name ?n]
[(vector ?y ?n) ?tuple]]
(d/db conn))
This relies on the implicit ordering from the first element, but how does it behave for multiple maxes? This returns:
[[[2011 "Love"]]]
But without max, we can see the one pulled by max was not unique:
[[2011 "1"]] [[2011 "Love"]]
If you know how many to expect, you could set, e.g.:
:find (max 2 ?tuple)
But this is taking us down a road best avoided. For most instances it makes sense to prefer the simple, more robust case of combining queries.
Upvotes: 5