PyMongo - Nama harus berupa turunan dari Str

Saya mencoba membaca dan menulis dari database di MongoDB Atlas dan meskipun saya dapat membaca data dari koleksi saya dengan baik, setiap upaya untuk menulis ke koleksi menyebabkan PyMongo memunculkan pengecualian 'nama harus berupa turunan str'.

Saya kira ini mengacu pada objek MongoClient tetapi masalahnya adalah saya menggunakan string koneksi. Adakah yang bisa membantu saya dengan kesalahan yang saya lakukan?

Kode saya adalah sebagai berikut: (Saya punya banyak komentar untuk membantu saya memahami lebih baik, jadi mohon maaf karena kurang singkatnya)

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

Kode Database saya adalah sebagai berikut:

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

person kilokahn    schedule 01.10.2017    source sumber


Jawaban (1)


Di "setattributes()", Anda mengakses instance Koleksi pymongo berdasarkan nama:

collection = db.database[self.tablename]

Kemudian di "insertdata()" Anda mencoba melakukan hal yang sama lagi, tetapi sekarang "koleksi" bukan string, melainkan instance Koleksi:

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

Sebagai gantinya, lakukan saja:

post_id = collection.insert_one(post).inserted_id

Ngomong-ngomong, saya melihat Anda telah menulis beberapa kode untuk memastikan Anda membuat dan menutup MongoClient untuk setiap operasi. Ini terlalu rumit dan akan memperlambat aplikasi Anda secara drastis karena memerlukan koneksi baru untuk setiap operasi. Seperti yang tercantum dalam FAQ, "Buat klien ini satu kali untuk setiap proses, dan gunakan kembali untuk semua operasi. Merupakan kesalahan umum untuk membuat klien baru untuk setiap permintaan, yang sangat tidak efisien."

Saya sarankan Anda menghapus kelas UseDatabase Anda, menjadikan MongoClient sebagai variabel global modul, dan menggunakan MongoClient secara langsung:

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)

Kode ini lebih sederhana dan akan berjalan lebih cepat.

person A. Jesse Jiryu Davis    schedule 01.10.2017
comment
Terima kasih banyak, saran Anda berhasil. Saya juga mengikuti saran Anda untuk memindahkan kelas database dan mengimplementasikan koneksi di thread utama itu sendiri - kelas ini adalah sisa dari versi aplikasi saya sebelumnya di mana saya menggunakan MariaDB dengan pengumpulan koneksi. Terima kasih banyak sekali lagi. :) - person kilokahn; 01.10.2017
comment
Apakah praktik yang baik jika koneksi bersifat global? Bukankah itu akan mempersulit pengujian dan juga memperburuk jika Anda melakukan transaksi? - person badc0re; 26.12.2018
comment
@ badc0re seperti yang disebutkan dalam dokumentasi, pyMongo mengimplementasikan pengumpulan koleksi di tingkat driver. Semakin sering Anda membuka/menutup koneksi, semakin lambat aplikasi Anda, dan jumlah koneksi yang terbuka ke DB pada waktu tertentu. - person kilokahn; 26.02.2019