0

I have a function that takes in list of entry and save it to mongo using monger. What is strange is that only the one record will be updated and the rest ignored unless I specify multi:true. I don't understand why the multi flag is necessary for monger to persist all the updates to mongodb.

(defn update-entries
   [entries]
   (let [conn (mg/connect)
         db (mg/get-db conn "database")]
     (for [e entries] (mc/update db "posts" {"id" (:id e)} {$set {:data (:data e)}} {:multi true}))))
Teo Choong Ping
  • 12,512
  • 18
  • 64
  • 91

1 Answers1

2

The multi flag is necessary for multi updates, since that's what mongo itself uses. Take a look at documentation for update. Granted, that's mongo shell, but most drivers try to follow when it comes to operation semantics.

Note that if "id" is unique, then you're updating one record at a time so having :multi set to true shouldn't matter.

There is, however, another issue with your code.

You use a for comprehension, which in turn iterates a collection lazily, i.e. calls to mc/update won't be made until you force the realization of the collection returned by for.

Since mc/update is a call made for it's side-effects (update a record in the db), using doseq would be more apropriate, unless you need the results.

If that's the case, wrap for in doall to force realization:

(doall 
    (for [e entries] 
         (mc/update db "posts" {"id" (:id e)} {$set {:data (:data e)}} {:multi true})))))
soulcheck
  • 36,297
  • 6
  • 91
  • 90
  • I originally used `doseq` but because I am not seeing the updates so I changed to `for` to see the output. I understand what you explained and you said it yourself that because I am matching 'id' so setting multi:true should not matter -- however this is the problem I am trying to understand. – Teo Choong Ping Sep 28 '14 at 14:39
  • 1
    @SeymourCakes if you need the results, you can use `doall` instead of `doseq`. Anyway you need to force the sequence realization somehow. – soulcheck Sep 28 '14 at 14:46