Welcome! Please see the About page for a little more info on how this works.

0 votes
in REPL by

Hi all,

I have a script that updates data in a MongoDB database using the monger library. All updates are performed when I open a repl and copy/paste the code, but I can't get it to work with lein run.

The relevant code:

(ns covid-data-management.core
(:require [oz.core :as oz]
                  [monger.core :as mg]
                  [monger.collection :as mc]))
(defonce db (mg/get-db (mg/connect) "covid19"))
(def coll "surveys")
(defn update-symptoms []
    (println "In the update-symptoms definitions")
    (map (fn [x]
            (mc/update db coll {} {"$set" {:symptoms ["symptom1" "symptom2"]}}))))

(defn main [& args]

Copy/pasting the code in the REPL does exactly what it should do: set the new symptoms. When running with lein run, the string "In the update-symptoms definitions" is printed to the console, but the database itself is not changed.

I suspect that it has to do with the no-side-effects and lazy features of clojure but haven't found the solution yet. Any help appreciated!

Thank you,

2 Answers

+3 votes

map is lazy. You will probably get better results if you wrap the (map ...) call inside of a (doall (map ...)) call, or if you use mapv (which is eager) instead of map.

Note that in a REPL, the P (Print) part of REPL will force a lazy return value from map to be fully evaluated so that it can be printed.

`doall` is a safe all-purpose quick fix for just about any conundrum that has to do with laziness.  But, If the return value does not matter (only the side effects matter), `dorun` would be clearer and `doseq` could be more direct and idiomatic.
Since Clojure 1.7, I'd probably use run! instead of doseq here, as the usage is exactly like map/mapv but it's eager and throws away the result of each function call.
0 votes

Something in your code may depend on your env vars.

Your REPL ENV is the same of your lein run env?

You can debug with (prn (System/getenv))

Env is exactly the same for both...