Question:
I have this code in Python
from pymongo import MongoClient
db = MongoClient('localhost', 27017)['myDB']['myCol']
params = { "model": "ILX ACURA" }
asset = { "newAsset": ["Foo", "Bar", "Poo"] }
document = { "$push": { "models.$[mod].years": asset } }
filters = { "arrayFilters" : [ { "mod.model": params['model'] } ] }
updated = db.update( {}, document, False, False, None, filters )
if updated.matched_count > 0:
print 'DONE!'
When I run the script I get this error
WriteError: No array filter found for identifier 'mod' in path models.$[mod].years
I've been struggling with python for a long time and tried better in MongoDB console
db.myCol.updateOne({}, { $push: { "models.$[mod].years": { "newAsset": ["Foo", "Bar","Poo"] } } }, { arrayFilters: [ { "mod.model": "ILX ACURA" } ] } )
Surprise!
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
What will be happening?
I use python 2.7 pymongo 3.8 mongoDB 4.0
Answer:
As @JackNavaRow points out in his opportune comment, the filters you apply must be passed in a list and not in a document as you have it, however that is not the only problem.
According to the PyMongo
documentation the update
method is deprecated , and it is suggested to use one of the methods: replace_one
, update_one
or update_many
.
We will use update_one
and you will be able to perform the task, I also suggest that whenever you try to perform operations on the database you use try except
blocks
Your code could look like this:
from pymongo import MongoClient
db = MongoClient('localhost', 27017)['myDB']['myCol']
params = { "model": "ILX ACURA" }
asset = { "newAsset": ["Foo", "Bar", "Poo"] }
# llamamos update al documento que representa la actualización, así no hay confusión
# con el documento que se está actualizando
update = { "$push": { "models.$[mod].years": asset } }
# filters es una lista, no un documento, cada elemento de la lista define un filtro
filters = [ { "mod.model": params['model'] } ]
#usamos un bloque try except
try:
updated = db.update_one( {}, update, False, False, None, filters )
if updated.matched_count > 0:
print 'DONE!'
except Exception, e:
print str(e)
This should do what you're trying to do (for 1 document).
Edition
Since you seem to be trying to update multiple documents, you should use update_many
.
Your code changes, since the order of the arguments passed to the method is different. You can consult the documentation .
from pymongo import MongoClient
db = MongoClient('localhost', 27017)['myDB']['myCol']
params = { "model": "ILX ACURA" }
asset = { "newAsset": ["Foo", "Bar", "Poo"] }
# llamamos update al documento que representa la actualización, así no hay confusión
# con el documento que se está actualizando
update = { "$push": { "models.$[mod].years": asset } }
# filters es una lista, no un documento, cada elemento de la lista define un filtro
filters = [ { "mod.model": params['model'] } ]
#usamos un bloque try except
try:
# usamos update_many
updated = db.update_many( {}, update, False, filters )
if updated.matched_count > 0:
#si deseamos ver la cantidad de documentos afectados:
print updated.matched_count
print 'DONE!'
except Exception, e:
print str(e)
I hope this is what you were looking for.