Outer Joins

In the relational database world, outer joins allow you to return relations even when data is missing from one side of a join. For example, you might want all of the mbrainz artists and their start years, including artists who do not even have a start year.

In Datomic, you can find the entities you want with datalog, and then make an independent decision about which details you want to pull. The following example uses query to find the artists, and then plugs in a pull pattern to get both the artist name and start year:

(def find-expr '[:find (pull ?e details-expr)
                 :in $ details-expr
                 :where [?e :artist/name]])
(def details-expr [:artist/name :artist/startYear])
(d/q find-expr db details-expr)

The query/pull separation also makes it easy to reuse query and pull logic independently.

Datomic also includes the get-else query function, which is closer to a literal outer join in that you can reference a possibly-missing attribute in directly in datalog, specifying an alternate value when the attribute is missing. The example below replaces a missing start year with "Unknown".

[:find ?e ?name ?year
 [?e :artist/name ?name]
 [(get-else $ ?e :artist/startYear "Unknown") ?year]]

You can see the full code for this example in the Day of Datomic Cloud repo.