michaelklishin / monger

Monger is an idiomatic Clojure MongoDB driver with sane defaults, batteries included, well documented, low overhead
http://clojuremongodb.info
484 stars 104 forks source link

Arrayfilters doesn't work #181

Closed p4ulcristian closed 5 years ago

p4ulcristian commented 5 years ago

This is my clojure function: (mc/update db "barbers" {} {"$set" {"members.$[elem].text" "hellothere"}} {"arrayFilters" [{"elem.id" {"$eq" 1}}]})

The error I get is: WriteConcernException Write failed with error code 2 and error message 'No array filter found for identifier 'elem' in path 'members.$[elem].text'' com.mongodb.operation.BaseWriteOperation.convertBulkWriteException (BaseWriteOperation.java:194)

The same in mongodb shell works: db.barbers.update({},{$set :{"members.$[elem].text" :"hellothere"}},{"arrayFilters" : [{"elem.id": {$eq : 1}}]})

It returns WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

seancorfield commented 5 years ago

Based on the source code for update it looks like it should be called with:

Try this instead:

(mc/update db "barbers" {} {"$set" {"members.$[elem].text" "hellothere"}} {"arrayFilters" [{"elem.id" {"$eq" 1}}}} {:multi true})

i.e., move just :multi out into the options argument map.

p4ulcristian commented 5 years ago

arrayFilters is a part of the options. Anyway I don't need the multi option, because I have distinct documents. So I updated my question without :multi true option

seancorfield commented 5 years ago

Ah, I misread the nesting of the maps. Well, Monger doesn't pay attention to anything in the options map except multi, upsert, and write-concern so if arrayFilters truly is an option, Monger won't pass it to the MongoDB. See https://github.com/michaelklishin/monger/blob/6bf528ed5b8a21153e3df1aa0cd1d88e08f31e3a/src/clojure/monger/collection.clj#L265

p4ulcristian commented 5 years ago

Thank you for you help. Do you know any way of "hacking" this? Like, for example how could I use mongo shell from clojure.

p4ulcristian commented 5 years ago

Well, I found my "hack" using mg/command.

(from-db-object (mg/command db (sorted-map :update "barbers" :updates [{:q {} :u {"$set" {"members.$[elem].text" "hellothere"}} :arrayFilters [{"elem.id" {"$eq" 1}}]}])) true)