{"id":15481785,"url":"https://github.com/haduart/flycouchdb","last_synced_at":"2026-02-28T05:37:13.760Z","repository":{"id":27122574,"uuid":"30590845","full_name":"haduart/flycouchdb","owner":"haduart","description":"Migration tool for CouchDB","archived":false,"fork":false,"pushed_at":"2015-05-18T13:00:53.000Z","size":7850,"stargazers_count":20,"open_issues_count":8,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-02T12:55:20.026Z","etag":null,"topics":["clojure","couchdb","database","schema"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haduart.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-10T12:22:41.000Z","updated_at":"2020-05-19T02:52:13.000Z","dependencies_parsed_at":"2022-09-11T13:04:45.364Z","dependency_job_id":null,"html_url":"https://github.com/haduart/flycouchdb","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/haduart/flycouchdb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haduart%2Fflycouchdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haduart%2Fflycouchdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haduart%2Fflycouchdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haduart%2Fflycouchdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haduart","download_url":"https://codeload.github.com/haduart/flycouchdb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haduart%2Fflycouchdb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29925683,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T19:37:42.220Z","status":"online","status_checked_at":"2026-02-28T02:00:07.010Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","couchdb","database","schema"],"created_at":"2024-10-02T05:06:10.918Z","updated_at":"2026-02-28T05:37:13.726Z","avatar_url":"https://github.com/haduart.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FlyCouchDB [![alt text][1.1]][1]\n[![Build Status](https://travis-ci.org/haduart/flycouchdb.svg)](https://travis-ci.org/haduart/flycouchdb) [![Dependency Status](https://www.versioneye.com/user/projects/54dafaf4c1bbbd9bd70003b1/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54dafaf4c1bbbd9bd70003b1) [![Coverage Status](https://coveralls.io/repos/haduart/flycouchdb/badge.svg?branch=master)](https://coveralls.io/r/haduart/flycouchdb?branch=master) [![marginalia docs](http://b.repl.ca/v1/doc-marginalia-blue.png)](https://haduart.github.io/flycouchdb/marginalia/uberdoc.html) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/haduart/flycouchdb?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge) [![endorse](https://api.coderwall.com/haduart/endorsecount.png)](https://coderwall.com/haduart)\n\n### CouchDB Migrations Made Easy!\n![alt text](https://raw.githubusercontent.com/haduart/flycouchdb/master/test/resources/Flying_red_couch.jpg \"FlyCouchDB\")\n\n[1.1]: http://i.imgur.com/tXSoThF.png (twitter icon with padding)\n[1]: https://twitter.com/flycouchdb\n[2]: https://twitter.com/haduart\nFlyCouchDB is a [clojure](http://clojure.org) migration tool for [Apache CouchDB](http://couchdb.apache.org/) inspired\nin what [Flywaydb](http://flywaydb.org) does for a relational database.\n\nAnd why would I need a migration tool for a flexible/schemaless database? because even if your database\nis schemaless that doesn't mean that there's no schema or structure in your data:\n\n*\"Usually when you're talking to a database you want to get some specific pieces of data out of it:\nI'd like the price, I'd like the quantity, I'd like the customer. As soon as you are doing that\nwhat you are doing is setting up an implicit schema. You are assuming that an order has a price\nfield. You are assuming tha is called 'price', not cost, or 'price to customer' or whatever.\nThat implicit schema is still in place and you've got to manage that implicit schema in many\nways in a similar approach that you manage the relational database.\"*\nFrom [Introduction to NoSQL](https://www.youtube.com/watch?v=qI_g07C_Q5I#t=11m30) by Martin Fowler.\n\nFlyCouchDB helps you maintaining an ordered migration list, allowing you to forget which migration has been run\nin a certain server. Just run the migrations and FlyCouchDB would start running from last ran migration:\nno mistakes, no migrations applied twice, no problems! Your data would be always in the state that you want,\nso you also can forget about adding hacks in your code depending if that field exist or not!\n\nEvolve your database schema easily and reliably across all your instances!\n\n## Current Version\n\n[![Clojars Project](http://clojars.org/flycouchdb/latest-version.svg)](http://clojars.org/flycouchdb)\n\nWith Maven:\n\n```bash\n\u003cdependency\u003e\n  \u003cgroupId\u003eflycouchdb\u003c/groupId\u003e\n  \u003cartifactId\u003eflycouchdb\u003c/artifactId\u003e\n  \u003cversion\u003e0.2.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nWith Gradle:\n```bash\ncompile \"flycouchdb:flycouchdb:0.2.1\"\n```\n\n### Works on\n\nWindows, Mac OSX, Linux, Java or even as a deployable war inside JBoss/Wildfly, Tomcat, Jetty.\n\n## Usage\n\nYou can run the migrations inside your own project or creating a separate one that will be run independently\nwhenever you execute it as an executable jar or as a deployable war.\n\nFor this example we will create a simple jar migration project. You can find a similar example project with\nmore advanced migrations here: [FlyCouchDB-example](https://github.com/haduart/flycouchdb-example).\n\nHere you can find an example on how to run FlyCouchDB inside a webapp: [FlyCouchDB Webapp Example](https://github.com/haduart/flycouchdb-webproject-example)\n\nFirst create a clojure project (it could also work inside a Java project or Scala):\n```bash\nlein new flycouchdb-example\n```\n\nIn the `project.clj` add the dependency to flycouchdb with the latest stable version:\n\n```clojure\n(defproject flycouchdb-example \"0.1.0-SNAPSHOT\"\n  :description \"Example project for FlyCouchDB\"\n  :url \"https://github.com/haduart/flycouchdb-example\"\n  :license {:name \"BSD\"\n            :url \"http://www.opensource.org/licenses/BSD-3-Clause\"}\n  :dependencies [[org.clojure/clojure \"1.6.0\"]\n                 [flycouchdb \"0.2.1\"]]\n```\n\nCreate a migrations folder inside your resources folder and put there your migrations.\n\nThen just create a clojure main entry point where you will run the migrations from that folder:\n\n```clojure\n(ns flycouchdbexample.core\n  (:use [clojure.java.io :only (file resource)]\n        [flycouchdb.migration :only (migrate flycouchdb)])\n  (:gen-class))\n\n(def folder-path (resource \"migrations\"))\n\n(def flydb (flycouchdb folder-path))\n\n(defn -main\n  [\u0026 args]\n  (do\n    (println \"Running migrations\")\n    (migrate flydb)\n    (println \"Done!\")))\n```\n\nBuild it:\n```bash\nlein do clean, uberjar\n```\n\nAnd run it:\n```bash\n lein run\n```\n or\n```bash\n java -jar flycouchdb-example-0.1.0-SNAPSHOT-standalone.jar\n```\n\n## Migrations\n\nEach migration is a file that contains an edn specific structure depending on the\naction that you want to run. The file should strictly follow this format:\n\n`V{VERSION_NUMBER}_{SUBVERSION_NUMBER}__MIGRATION-DESCRIPTION-TEXT.edn`\n\nex. `V1_131__Create_Database.edn`\n\nThe migrations will be run depending on the order of the version first, and within\nmigrations from the same version they will be ordered depending on the subversion\nnumber.\n\nSo `V1_131__Create_Database.edn` will be run before `V1_132__Delete_Database.edn`,\nand both of them will be run before `V2_1__Create_another_Database.edn`.\n\nIn each migration file it can only be one edn structure representing one action,\nexcept of the compose actions that can execute multiple actions.\n\nSo far for the current version there's a minimum set of actions that you can execute:\n- Create Database\n- Delete Database\n- Create View\n- Rename Keys\n- Edit Documents\n- Insert Documents\n- Composing actions\n\n### Create Database\n\nThis action will create a database in CouchDB.\n\n```clojure\n{:dbname \"edu-db\"\n :action :create}\n```\n\n`:dbname` indicates the name of the new database that will be created.\n\n### Delete Database\n\nThis action will delete a database in CouchDB with all the documents that contains.\n\n```clojure\n{:dbname \"edu-db\"\n :action :delete}\n```\n\n`:dbname` indicates the name of the new database that will be deleted.\n\n### Create View\n\nThis action will create a view in CouchDB.\n\n```clojure\n{:dbname      \"edu-db\"\n :action      :create-view\n :create-view {:view-design   \"view-design\"\n               :view-name     \"view-name\"\n               :function-type \"javascript\"\n               :view-function \"function(doc) {if (doc.username \u0026\u0026 doc.username ==='eduard') {emit(doc._id, doc);}}\"}}\n```\n\n`:dbname` indicates the name of the database where the view will be created.\n`:view-design` indicates the name of the design template in CouchDB. Usually one\nCouchDB design can contain multiple views, but there's a bug in the current [clutch](https://github.com/clojure-clutch/clutch)\nlibrary. So it's better to use a new design template per view.\n`:view-name` indicates the name of the view in CouchDB.\n`:function-type` this will indicate if the migration will be written in `javascript`,\n`clojurescript` or `clojure`. So far only javascript is allowed.\n`:view-function` this will be the javascript function that will create the view.\n\n### Rename Keys\n\nThis action will rename using the rename-fun all the keys (all the id) that\nmatches the filter-fn. CouchDB does not support renaming the keys or teh version\nnumber! so internally will delete the documents and will create them again with\nthe new key!\n\n```clojure\n{:dbname      \"edu-db\"\n :action      :rename-keys\n :rename-keys {:filter-fn (fn [x] true)\n               :rename-fn (fn [{id :_id}] (str id \"-new-end\"))}}\n```\n\n`:filter-fn` Is a function that will test whether a document should be renamed or not.\nReturning true or false. That function receives as an argument the document itself,\nso it can check any entry inside the document.\n`:rename-fn` In case the filter-fn returns true this function will be applied.\nThis function should return a string that will be the value of the new key.\n\n### Edit Documents\n\nThis action will edit a document, adding a new entry, removing it or modifying one\nwhenever the filter-fn allows it.\n\n```clojure\n{:dbname       \"edu-db\"\n :action       :edit-entries\n :edit-entries {:filter-fn (fn [{count :count}] (\u003c 10 count))\n                :edit-fn (fn [entry] (assoc entry :new-key \"new value\"))}}\n```\n\n`:filter-fn` Is a function that will test whether a document should be edited or not.\nReturning true or false. That function receives as an argument the document itself,\nso it can check any entry inside the document.\n`:edit-fn` In case the filter-fn returns true this function will be applied.\nThis function should return a string that will be the value of the new key.\n\n### Insert Documents\n\nThis action will insert documents inside a database. Useful to create the initial\ndatabase or to create dummy data.\n\n```clojure\n{:dbname           \"database-0\"\n :action           :insert-documents\n :insert-documents {:insert-documents-fn\n                    (fn [] [{:_id  \"1\"\n                             :name \"Eduard\" :surname \"Cespedes Borras\"\n                             :mail \"haduart@gmail.com\"}])}}\n```\n\n`:insert-documents-fn` Is an anonymous function that will return a vector with the\n documents that has to be inserted. It expects that the `:_id` will be the key of\n the document and this will be unique.\n\n Of course you can use any clojure code to generate this list of documents:\n\n```clojure\n{:dbname           \"eduard-db\"\n :action           :insert-documents\n :insert-documents {:insert-documents-fn\n                    (fn [] (-\u003e\u003e\n                             (range 1 1000)\n                             (mapv (fn [x] {:_id     (str x)\n                                            :name    (str \"user-\" x)\n                                            :mail    (str \"user-\" x \"@gmail.com\")\n                                            :minimum (rand-int 500)\n                                            :maximum (rand-int 1200)}))))}}\n```\n\n### Composing actions\n\nThis action allows you to execute multiple actions. You can even create them\nin a programmatically way.\n\n```clojure\n{:action    :composite\n :composite {:composite-fn (fn [] [{:dbname \"database-0\" :action :create}\n                                   {:dbname \"database-0\" :action :delete}\n                                   {:dbname \"database-2\" :action :delete}\n                                   {:dbname \"database-3\" :action :delete}])}}\n```\n\n`:composite-fn` Is an anonymous function that will return a vector of migrations or\nactions.\n\nOf course, like everywhere, you can use any clojure code to generate this list of actions:\n\n```clojure\n{:action    :composite\n :composite {:composite-fn (fn [] (-\u003e\u003e\n                                    10\n                                    range\n                                    (map (fn [x] {:dbname (str \"database-\" x)}))\n                                    (mapv (fn [db] (assoc db :action :create)))))}}\n```\n\nIt even allows you to do advanced database manipulations like never before!\n\n```clojure\n{:action    :composite\n :composite {:composite-fn (fn []\n                             (let [db (be.dsquare.clutch/couch \"eduard-db\")\n                                   user-view (be.dsquare.clutch/get-view db \"view-design\" \"view-name\")\n                                   results-in-view (take (count user-view) user-view)\n                                   averages (atom {})]\n                               (do\n                                 (-\u003e\u003e\n                                   results-in-view\n                                   (map #(:value %))\n                                   (map (fn [{:keys [maximum minimum id]}] {:_id id :average (double (/ (+ maximum minimum) 2))}))\n                                   (mapv (fn [x] (swap! averages assoc (:_id x) (dissoc x :_id)))))\n\n                                 [{:dbname       \"eduard-db\"\n                                   :action       :edit-entries\n                                   :edit-entries {:filter-fn (fn [{id :_id}] (not (nil? (get @averages id))))\n                                                  :edit-fn   (fn [entry] (merge entry (get @averages (:_id entry))))}}])))}}\n```\n\n## Changelog\n\n### v0.2.2-SNAPSHOT\n* delete-documents action\n\n### v0.2.1\n* Added support to JBoss VFS. Not it also works in JBoss EAP 5,6 and WildFly\n\n### v0.2.0\n* Running inside a JAR\n* Running as a normal Clojure project.\n* Initial actions are supported: Create Database, Delete Database, Create View, Rename Keys, Edit Documents, Insert Documents and Composing actions.\n\n## Contributors\n\n* **(Author)** [Eduard Cespedes Borras](https://github.com/haduart) [![alt text][1.1]][2]\n* [Roberto Barchino Garrido](https://github.com/fisoide)\n* [Igor Ruzanov](https://github.com/r00z)\n* [Jeroen Hoekx](https://github.com/jhoekx)\n\n\n## Sponsored\nThis project is sponsored by [D square N.V](http://dsquare.be)\n\n\n## License\n\nBSD.  See the LICENSE file at the root of this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaduart%2Fflycouchdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaduart%2Fflycouchdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaduart%2Fflycouchdb/lists"}