【问题标题】:PyMongo - Name must be an instance of StrPyMongo - 名称必须是 Str 的实例
【发布时间】:2018-03-12 15:27:27
【问题描述】:

我正在尝试从 MongoDB Atlas 上的数据库读取和写入,虽然我可以从我的集合中读取数据就好了,任何写入集合的尝试都会导致 PyMongo 引发异常 'name must be an instance of str '。

我猜这是对 MongoClient 对象的引用,但问题是我使用的是连接字符串。谁能帮我解决我做错了什么?

我的代码如下:(我有大量的 cmets 可以帮助我更好地理解,所以请原谅不够简洁)

def setattributes(self, rowdict):
        """ a function to create a user. Assumes that only a data
        dict is provided. strips everything else and updates.
         what the data dict contains is your problem.
        """
        with UseDatabase(self.dbconfig) as db:
            collection = db.database[self.tablename]
            locationdict = {    #create a corresponding location entry
            'email' : rowdict['email'],
            'devstate' : 0,
            'location' : {
            'type': 'Point',
            'coordinates' : [ 0, 0 ]
            },
            'lastseen' : datetime.now()
            }
            try:
                res = db.insertdata(collection, rowdict) #insert user data
            except Exception as e:
                print("Error adding user to DB : %s" % e)
                return False  # if you cant insert, return False
            try:  
                loccollection = db.database[self.locationtable]
                resloc = db.insertdata(loccollection, locationdict)
            except Exception as e: # if the status update failed
                db.collection.remove({'email' : rowdict['email']}) 
                #rollback the user insert - atomicity
                return False
        return True

我的数据库代码如下:

class ConnectionError(Exception):
    pass

class CredentialsError(Exception):
    pass

class UseDatabase:
    def __init__(self, config: dict):
        self.config = config

    def __enter__(self, config = atlas_conn_str):
        try:
            self.client = MongoClient(config)
            self.database = self.client['reviv']
            return self

        except:
            print("Check connection settings")
            raise ConnectionError

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.client.close()

    def insertdata(self, collection, data):
        post = data
        post_id = self.database[collection].insert_one(post).inserted_id
        return post_id

    def getdetails(self, collection, emailid):
        user = collection.find_one({'email' : emailid}, {'_id' : 0})
        return user

【问题讨论】:

    标签: mongodb python-3.x pymongo


    【解决方案1】:

    在您的“setattributes()”中,您可以按名称访问 pymongo Collection 实例:

    collection = db.database[self.tablename]
    

    然后在“insertdata()”中你尝试再次做同样的事情,但现在“collection”不是一个字符串,它是一个 Collection 实例:

    post_id = self.database[collection].insert_one(post).inserted_id
    

    相反,只需这样做:

    post_id = collection.insert_one(post).inserted_id
    

    顺便说一句,我看到您已经编写了一些代码来确保为每个操作创建和关闭 MongoClient。这不必要地复杂,并且会因每次操作都需要新连接而大大减慢您的应用程序。 As the FAQ says, "为每个进程创建一次这个客户端,所有操作都重复使用它。为每个请求创建一个新客户端是一个常见的错误,效率非常低。"

    我建议你删除你的 UseDatabase 类,将 MongoClient 设为模块全局变量,然后直接使用 MongoClient:

    client = MongoClient(atlas_conn_str)
    db = client[locationtable]
    
    class C:
        def setattributes(self, rowdict):
            collection = db[self.tablename]
            # ... make rowdict as usual, and then:
            res = collection.insert_one(rowdict)
    

    此代码更简单,运行速度更快。

    【讨论】:

    • 非常感谢,您的建议成功了。我还听取了您关于将数据库类移出并在主线程本身中实现连接的建议 - 这个类是我使用 MariaDB 和连接池的早期版本的应用程序的残余。再次非常感谢。 :)
    • 全局连接是个好习惯吗?如果您有交易,那不会使测试复杂化并且还会使情况变得更糟吗?
    • @badc0re 正如文档所说,pyMongo 在驱动程序级别实现集合池。您打开/关闭连接的次数越多,您的应用程序就越慢,并且在任何给定时间打开到数据库的连接数。
    猜你喜欢
    • 2021-03-03
    • 1970-01-01
    • 2021-06-20
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    • 2012-05-04
    相关资源
    最近更新 更多