MongoDB优化了多个find_one+插入内部循环



我正在使用MongoDB 4.0.1和pymongo与pyhton 3.5。我必须每 30 - 60 秒循环 12000 个项目,并将新数据添加到 MongoDB 中。在本例中,我们将讨论用户、宠物和汽车。用户可以获得1辆车和1只宠物。

我需要宠物 ObjectID 和汽车 ObjectID 来创建我的用户,所以我必须在循环中一个接一个地添加它们,这非常慢。查找现有数据并在数据不存在时添加它们需要 ~25 秒。

while dictionary != False:
# Create pet if not exist
existing_pet = pet.find_one({"code": dictionary['pet_code']})
if bool(existing_pet):
pet_id = existing_pet['_id']
else:
pet_id = pet.insert({
"code" : dictionary['pet_code'],
"name" : dictionary['name']
})
# Call web service to create pet remote
# Create car if not exist
existing_car = car.find_one({"platenumber": dictionary['platenumber']})
if bool(existing_car):
car_id = existing_car['_id']
else:
car_id = car.insert({
"platenumber" : dictionary['platenumber'],
"model" : dictionary['model'],
"energy" : 'electric'
})
# Call web service to create car remote
# Create user if not exist
existing_user = user.find_one(
{"$and": [
{"user_code": dictionary['user_code']},
{"car": car_id},
{"pet": pet_id}
]}
)
if not bool(existing_user):
user_data.append({
"pet" : pet_id,
"car" : car_id,
"firstname" : dictionary['firstname'],
"lastname" : dictionary['lastname']
})
# Call web service to create user remote
# Bulk insert user
if user_data:
user.insert_many(user_data)

我为用于find_one的每一列创建了索引:

db.user.createIndex( { user_code: 1 } )
db.user.createIndex( { pet: 1 } )
db.user.createIndex( { car: 1 } )
db.pet.createIndex( { pet_code: 1 }, { unique: true }  )
db.car.createIndex( { platenumber: 1 }, { unique: true }  )

有没有办法加快这个循环?有一些聚合或其他东西可以帮助我?或者也许另一种方式可以做我想做的事?

我愿意接受所有建议。

不要执行 12000 个find_one查询,执行 1 个查询以使用运算符$in所有存在的内容。代码如下所示:

pet_codes = []
pet_names = []
while dictionary != False:
pet_codes.append(dictionary['pet_code'])
pet_names.append(dictionary['pet_name'])
pets = dict()
for pet in pet.find({"code": {$in: pet_codes}}):
pets[pet['code']] = pet
new_pets = []
for code, name in zip(pet_codes, pet_names):
if code not in pets:
new_pets.add({'pet_code': code, 'name': name})
pet.insert_many(new_pets)

由于您已经有一个索引pet_code使其唯一,我们可以做得更好:只需尝试将它们全部插入,因为如果我们尝试插入现有记录,该记录将出现错误,但其余的将使用文档中的 ordered=False 成功:

new_pets = []
while dictionary != False:
new_pets.add({
"code" : dictionary['pet_code'],
"name" : dictionary['name']
})
pet.insert_many(new_pets, ordered=False)

如果您没有唯一限制集,另一种方法是批处理操作

最新更新