0

I'm creating a script using MongoEngine to update a collection. The update needs to modify a specific field within a ListField.
Using raw pyMongo, the update would look like this:

db.books.update({"authors": {"$elemMatch": {"$eq": "matt"}}}, {'$set': {"authors.$": "Mathew"}}).

Unfortunately I have to do this in MongoEngine (Since the rest of the system works with it and I need it for consistency) and since this could be a very large collection, I prefer mongo handles the update rather than load the entire collection and update each element of books in my python code.

I tried doing the same request with Mongo Engine:

class Book(DynamicDocument):
    meta = {'collection': 'books', 'strict': False}

    authors = ListField()

    @classmethod
    def update_author_name(cls, oldVal, newVal):
        filter = Q(**{"authors__in": [oldVal]})
        cls.objects(filter).update(**{authors+".$": newVal})

however, I get an exception:

{InvalidQueryError}field names cannot contain dots (".") or null characters ("\0"), and they must not start with a dollar sign ("$").
Nox Noctis
  • 114
  • 9

1 Answers1

1

mongoengine has no support for this, the best you could achieve is by using raw and get closer to pymongo syntax like this:

Book.objects(__raw__={"authors": {"$elemMatch": {"$eq": "Math"}}}).update(__raw__={'$set': {"authors.$": "Mathew"}})

But there is not much added value compared to getting to the actual collection and executing the query through pymongo

c = Book._get_collection()
c.update({"authors": {"$elemMatch": {"$eq": "matt"}}}, {'$set': {"authors.$": "Mathew"}})
bagerard
  • 5,681
  • 3
  • 24
  • 48