Skip to content

Instantly share code, notes, and snippets.

@klang
Created August 27, 2013 06:21
Show Gist options
  • Save klang/6350215 to your computer and use it in GitHub Desktop.
Save klang/6350215 to your computer and use it in GitHub Desktop.
Learn datolog today
;; http://www.learndatalogtoday.org/
;; Find movie titles made in 1985
[:find ?title
:where
[?m :movie/year 1985]
[?m :movie/title ?title]]
;; What year was "Alien" released?
[:find ?year
:where
[?e :movie/title "Alien"]
[?e :movie/year ?year]]
;; Who directed RoboCop?
;; You will need to use [<movie-eid> :movie/director <person-eid>]
;; to find the director for a movie.
[:find ?name
:where
[?m :movie/title "RoboCop"]
[?m :movie/director ?d]
[?d :person/name ?name]]
;; Find directors who has directed Arnold Schwarzenegger in a movie.
[:find ?name
:where
[?m :movie/cast ?c]
[?c :person/name "Arnold Schwarzenegger"]
[?m :movie/director ?d]
[?d :person/name ?name]]
;; Parameterized queries
;; Find movie title by year
1988
[:find ?title
:in $ ?year
:where
[?e :movie/title ?title]
[?e :movie/year ?year]]
;; Given a list of movie titles, find the title and the year that movie was released.
["Lethal Weapon" "Lethal Weapon 2" "Lethal Weapon 3"]
[:find ?title ?year
:in $ [?title ...]
:where
[?m :movie/year ?year]
[?m :movie/title ?title]]
;; Write a query that, given an actor name and a relation with movie-title/rating, finds the movie titles and corresponding rating for which that actor was a cast member.
"Mel Gibson"
[["Die Hard" 8.3]
["Alien" 8.5]
["Lethal Weapon" 7.6]
["Commando" 6.5]
["Mad Max Beyond Thunderdome" 6.1]
["Mad Max 2" 7.6]
["Rambo: First Blood Part II" 6.2]
["Braveheart" 8.4]
["Terminator 2: Judgment Day" 8.6]
["Predator 2" 6.1]
["First Blood" 7.6]
["Aliens" 8.5]
["Terminator 3: Rise of the Machines" 6.4]
["Rambo III" 5.4]
["Mad Max" 7.0]
["The Terminator" 8.1]
["Lethal Weapon 2" 7.1]
["Predator" 7.8]
["Lethal Weapon 3" 6.6]
["RoboCop" 7.5]]
[:find ?title ?rating
:in $ ?cast [[?title ?rating]]
:where
[?m :movie/title ?title]
[?m :movie/cast ?c]
[?c :person/name ?cast]]
;; More queries
;; What attributes are associated with a given movie.
[:find ?attr
:in $ ?title
:where
[?m :movie/title ?title]
[?m ?a]
[?a :db/ident ?attr]]
;; Find the names of all people associated with a particular movie
;; (i.e. both the actors and the directors)
"Die Hard"
[:movie/cast :movie/director]
[:find ?name
:in $ ?title [?attr ...]
:where
[?m :movie/title ?title]
[?m ?attr ?p]
[?p :person/name ?name]]
;; Find all available attributes, their type and their cardinality. This is essentially a query to find the schema of the database. To find all installed attributes you must use the :db.install/attribute attribute. You will also need to use the :db/valueType and :db/cardinality attributes as well as :db/ident.
[:find ?attr ?type ?card
:where
[?e :db.install/attribute ?a]
[?a :db/ident ?attr]
[?a :db/valueType ?t]
[?t :db/ident ?type]
[?a :db/cardinality ?c]
[?c :db/ident ?card]]
;; When was the seed data imported into the database? Grab the transaction of any datom in the database, e.g., [_ :movie/title _ ?tx] and work from there.
[:find ?inst
:where
[_ :movie/title _ ?tx]
[?tx :db/txInstant ?inst]]
;; Find movies older than a certain year (inclusive)
[:find ?title
:in $ ?limit-year
:where
[?e :movie/title ?title]
[?e :movie/year ?year]
[(<= ?year ?limit-year)]]
;; Find movies newer than ?year (inclusive) and has a ?rating higher than the one supplied
1990
8.0
[["Die Hard" 8.3]
["Alien" 8.5]
["Lethal Weapon" 7.6]
["Commando" 6.5]
["Mad Max Beyond Thunderdome" 6.1]
["Mad Max 2" 7.6]
["Rambo: First Blood Part II" 6.2]
["Braveheart" 8.4]
["Terminator 2: Judgment Day" 8.6]
["Predator 2" 6.1]
["First Blood" 7.6]
["Aliens" 8.5]
["Terminator 3: Rise of the Machines" 6.4]
["Rambo III" 5.4]
["Mad Max" 7.0]
["The Terminator" 8.1]
["Lethal Weapon 2" 7.1]
["Predator" 7.8]
["Lethal Weapon 3" 6.6]
["RoboCop" 7.5]]
[:find ?title
:in $ ?year ?rate [[?title ?rating]]
:where
[?e :movie/title ?title]
[?e :movie/year ?y]
[(<= ?year ?y)]
[(< ?rate ?rating)]]
;; Transformation functions
;; Find people by age. Use the function tutorial.fns/age to find the age given a birthday and a date representing "today".
63
#inst "2013-08-02T00:00:00.000-00:00"
[:find ?name
:in $ ?age ?today
:where
[?p :person/name ?name]
[?p :person/born ?born]
[(tutorial.fns/age ?born ?today) ?age]]
;; Find people younger than Bruce Willis and their ages.
#inst "2013-08-02T00:00:00.000-00:00"
[:find ?name ?age
:in $ ?today
:where
[?p :person/name ?name]
[?p :person/born ?born]
[?b :person/name "Bruce Willis"]
[?b :person/born ?bborn]
[(tutorial.fns/age ?bborn ?today) ?bage]
[(tutorial.fns/age ?born ?today) ?age]
[(< ?age ?bage)]]
;; ah, comparing the dates directly is legal. No need to calculate the age.
[:find ?name ?age
:in $ ?today
:where
[?p :person/name "Bruce Willis"]
[?p :person/born ?sborn]
[?p2 :person/name ?name]
[?p2 :person/born ?born]
[(< ?sborn ?born)]
[(tutorial.fns/age ?born ?today) ?age]]
;; The birthday paradox states that in a room of 23 people there is a 50% chance that someone has the same birthday. Write a query to find who has the same birthday. Use the < predicate on the names to avoid duplicate answers. You can use (the deprecated) .getDate and .getMonth java Date methods.
[:find ?name-1 ?name-2
:where
[?p1 :person/name ?name-1]
[?p1 :person/born ?born-1]
[?p2 :person/name ?name-2]
[?p2 :person/born ?born-2]
[(.getDate ?born-1) ?d1 ]
[(.getDate ?born-2) ?d2 ]
[(.getMonth ?born-1) ?m1 ]
[(.getMonth ?born-2) ?m2 ]
[(= ?d1 ?d2)]
[(= ?m1 ?m2)]
[(< ?name-1 ?name-2)]]
;; using duplicate versions of ?m and ?d elliminate the need to compare them.. nifty!
[:find ?name-1 ?name-2
:where
[?p1 :person/name ?name-1]
[?p2 :person/name ?name-2]
[?p1 :person/born ?born-1]
[?p2 :person/born ?born-2]
[(.getMonth ?born-1) ?m]
[(.getMonth ?born-2) ?m]
[(.getDate ?born-1) ?d]
[(.getDate ?born-2) ?d]
[(< ?name-1 ?name-2)]]
;; Aggregates
;; count the number of movies in the database
[:find (count ?e)
:where
[?e :movie/title]]
;; Find the birth date of the oldest person in the database.
[:find (min ?date)
:where
[?e :person/born ?date]]
;;Given a collection of actors and (the now familiar) ratings data. Find the avarage rating for each actor. The query should return the actor name and the avg rating.
["Sylvester Stallone" "Arnold Schwarzenegger" "Mel Gibson"]
[["Die Hard" 8.3]
["Alien" 8.5]
["Lethal Weapon" 7.6]
["Commando" 6.5]
["Mad Max Beyond Thunderdome" 6.1]
["Mad Max 2" 7.6]
["Rambo: First Blood Part II" 6.2]
["Braveheart" 8.4]
["Terminator 2: Judgment Day" 8.6]
["Predator 2" 6.1]
["First Blood" 7.6]
["Aliens" 8.5]
["Terminator 3: Rise of the Machines" 6.4]
["Rambo III" 5.4]
["Mad Max" 7.0]
["The Terminator" 8.1]
["Lethal Weapon 2" 7.1]
["Predator" 7.8]
["Lethal Weapon 3" 6.6]
["RoboCop" 7.5]]
[:find ?cast (avg ?rating)
:in $ [?cast ...] [[?title ?rating]]
:where
[?m :movie/title ?title]
[?m :movie/cast ?c]
[?c :person/name ?cast]]
;; Rules
;; Write a rule [movie-year ?title ?year] where ?title is the title of some movie and ?year is that movies release year.
[:find ?title
:in $ %
:where
(movie-year ?title 1991)]
[[(movie-year ?title ?year)
[?m :movie/year ?year]
[?m :movie/title ?title]]]
;; Two people are friends if they have worked together in a movie. Write a rule [friends ?p1 ?p2] where p1 and p2 are person entities. Try with a few different ?name inputs to make sure you got it right. There might be some edge cases here.
[:find ?friend
:in $ % ?name
:where
[?p1 :person/name ?name]
(friends ?p1 ?p2)
[?p2 :person/name ?friend]]
[[(friends ?p1 ?p2)
[?m :movie/director ?p1]
[?m :movie/cast ?p2]]]
"James Cameron"
;; ah, there is a difference between the cast and director ..
;; and "worked together" applies across that difference
;; "I give up"
[[(friends ?p1 ?p2) [?m :movie/cast ?p1] [?m :movie/cast ?p2]]
[(friends ?p1 ?p2) [?m :movie/cast ?p1] [?m :movie/director ?p2]]
[(friends ?p1 ?p2) (friends ?p2 ?p1)]]
;;Write a rule [sequels ?m1 ?m2] where ?m1 and ?m2 are movie entities. You'll need to use the attribute :movie/sequel. To implement this rule correctly you can think of the problem like this: A movie ?m2 is a sequel of ?m1 if either
;; ?m2 is the "direct" sequel of m1 or
;; ?m2 is the sequel of some movie ?m and that movie ?m is the sequel to ?m1.
;; There are (at least) three different ways to write the above query. Try to find all three solutions.
[:find ?sequel
:in $ % ?title
:where
[?m :movie/title ?title]
(sequels ?m ?s)
[?s :movie/title ?sequel]]
[[(sequels ?m1 ?m2) ...]]
"Mad Max"
[[(sequels ?m1 ?m2) [?m1 :movie/sequel ?m2]]
[(sequels ?m1 ?m2) [?m1 :movie/sequel ?m] [?m :movie/sequel ?m2]]]
;; "I give up"
[[(sequels ?m1 ?m2) [?m1 :movie/sequel ?m2]]
[(sequels ?m1 ?m2) [?m :movie/sequel ?m2] (sequels ?m1 ?m)]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment