Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Store arbitrary Clojure data in Datomic efficiently
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


monocopy is a library and schema for efficiently storing many Clojure value types in a Datomic database.

Supported types include strings, symbols, keywords, doubles, longs, and maps.

monocopy represents maps as sets of pairs. In order to make storage and query as efficient as possible, only distinct maps, pairs, and scalars are stored.

Dependency Build Status

[tailrecursion/monocopy "1.0.9"]

monocopy depends on com.datomic/datomic-free. To use it in a project that depends on com.datomic/datomic-pro, your dependency would be:

[tailrecursion/monocopy "1.0.9" :exclusions [com.datomic/datomic-free]]


(require '[tailrecursion.monocopy :refer [datoms hydrate] :as mc])
(require '[datomic.api            :refer [q db]           :as d])

;; create, connect to an in-memory database
(def uri "datomic:mem://monocopy")
(d/create-database uri)
(def conn (d/connect uri))

;; load in the monocopy schema
(d/transact conn mc/schema)

;; load in your application schema
(d/transact conn [{:db/doc "Attribute pointing to some monocopy data structure"
                   :db/ident :person/ref
                   :db/id #db/id [:db.part/db]
                   :db/valueType :db.type/ref
                   :db/cardinality :db.cardinality/one
                   :db.install/_attribute :db.part/db}
                  {:db/doc "Uniquely identifies this person"
                   :db/ident :person/id
                   :db/id #db/id [:db.part/db]
                   :db/valueType :db.type/uuid
                   :db/cardinality :db.cardinality/one
                   :db/unique :db.unique/identity
                   :db.install/_attribute :db.part/db}])

(def bob {:name "Bob" :age 39})

;; add Bob
(d/transact conn
            (let [id (d/tempid :db.part/user)]
              (concat [[:db/add id :person/id (java.util.UUID/randomUUID)]]
                      ;; datoms takes a value, parent entity id,
                      ;; and parent attribute to attach to
                      (datoms bob id :person/ref))))

;; query to find people named Bob
(def query
  '[:find ?person
    [?k1     :monocopy.keyword/value :name]
    [?e1     :monocopy.entry/key     ?k1]
    [?e1     :monocopy.entry/val     ?v1]
    [?v1     :monocopy.string/value  "Bob"]
    [?map    :monocopy/entries       ?e1]
    [?person :person/ref             ?map]])

;; find people named Bob
(let [db (d/db conn)]
  (map (comp #(update-in % [:person/ref] hydrate)
             (partial into {})
             (partial d/entity db)
       (d/q query db)))


monocopy uses the md5 hash of the printed value of collections as unique identifiers, so there is a possibility of hash collision and data loss.

Ultimately, we'd like to implement this Dynamic Perfect Hashing scheme and deal with collisions such that data is not lost.


Copyright (c) Alan Dipert. All rights reserved.
The use and distribution terms for this software are
covered by the Eclipse Public License 1.0
( which can be
found in the file epl-v10.html at the root of this
distribution. By using this software in any fashion, you are
agreeing to be bound by the terms of this license. You must not
remove this notice, or any other, from this software.
Something went wrong with that request. Please try again.