Search code examples
pythonmongodbtornado

'Collection' object is not callable. If you meant to call the 'save' method on a 'Collection' object it is failing because no such method exists


I am using tornado to build a simple website with mongoDB. I used python 3.7 and latest version of pymongo to control data in MongoDB but when I edit data in MongoDB with save methods as code below, the following error occurred:

TypeError: 'Collection' object is not callable. If you meant to call the 'save' method on a 'Collection' object it is failing because no such method exists.

    def post(self, isbn=None):
        import time
        book_fields = ['isbn', 'title', 'subtitle', 'image', 'author', 'date_released', 'description']
        burtbook = self.application.db.BurtBook
        book = dict()
        if isbn:
            book = burtbook.find_one({"isbn":isbn})
        for key in book_fields:
            book[key] = self.get_argument(key, None)

        if isbn:
            burtbook.save(book)
        else:
            book['add_released'] = int(time.time())
            burtbook.insert_one(book)
        self.redirect("/recommended/")

Please help me to fix this bug.


Solution

  • well, i dont know why, but i think there is a bug with save or its deprecated since end of 2020?

    the savior method will be: update_one($old_document, $keys_to_update)

    i saw on this reference that you can update in place a document and keep the ObjectID unmodified (you will have the original document id)

    your code will become (comments will explain everything)

    def post(self, isbn=None):
        import time
        book_fields = ['isbn', 'title', 'subtitle', 'image', 'author', 'date_released', 'description']
        burtbook = self.application.db.BurtBook
        book = dict()
        if isbn:
            book = burtbook.find_one({"isbn": isbn})
            # set is a specifier to mongo to update the values;
            # you just need to pass which value to modify on which key
            # example
            # keys_to_update = {"$set": { "bookName": "newNameSetByYou"}}
            # but the bookName key name remains the same
            keys_to_update = {"$set": {}}
    
        for key in book_fields:
            value = self.get_argument(key, None)
            book[key] = value
            if isbn:
                # here if isbn we create that dictionary to tell
                # mongo which value to modify on which key
                keys_to_update["$set"].update({
                    key: value
                })
                # simple and old pythonic dict update
    
        if isbn:
            # here we update the document book with new values
            # from the above generated dict
            burtbook.update_one(book, keys_to_update)
            # just like the save()
            # save is deprecated boys, cant use it anymore ...
        else:
            book['add_released'] = int(time.time())
            burtbook.insert_one(book)
        self.redirect("/recommended/")
    

    okey, on my defense, i couldnt test your code, but i've tested the same technique on my project and it know that it works for me.

    just tell me if it works. pace

    EDIT

    another helpful reference

    and also you can try this code too (here you replace the entire document with whatever you want):

    todos_collection = get_collection(todos_collection_name)
    requested_todo = todos_collection.find_one({
        "_id": ObjectId(oid)
    })
    
    todos_collection.replace_one(requested_todo, {"something": "else"})
    # this will replace the entire document `request_todo` with `{"something": "else"}`
    # but it will keep the original `ObjectID`
    # and thats is very useful