【问题标题】:MongoDB optimize multiple find_one + insert inside loopMongoDB优化多个find_one + insert inside循环
【发布时间】:2019-02-04 06:57:32
【问题描述】:

我正在使用 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 运算符带来所有存在
  • 你能举个例子吗?

标签: python mongodb optimization pymongo


【解决方案1】:

不要执行 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 上创建了唯一索引,因此我们可以做得更好:尝试将它们全部插入,因为如果我们尝试插入现有的记录会出错,但其余的将通过使用成功来自the docs 的ordered=False:

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

如果你没有唯一的限制集,另一种方法是batching the operations

【讨论】:

  • 我有一个问题,因为我失去了与他的用户的宠物关系。当我创建它时,我必须将 Pet 对象 ID 放在我的用户中
  • @John 你可以查询插入后的记录获取所有的pet_ids
  • 那么 find_one 会比 insert 快吗?我会在同一个字典上循环两次?首先插入,然后再次查找项目?
  • @John 不要使用 find_one,使用 find 来获取所有具有相同查询的内容,就像我的第一个示例中一样
  • 事实上,你的回答并没有解决我的问题:/。我不想将所有属性对象添加到不同的数组中。每个对象至少有 7 个属性。尝试用你解决我对所有对象(宠物、汽车和用户)所做的事情,你会发现它不起作用。而且我不知道如何查询每个对象的所有插入 id 以填充用户对象并为每个对象调用 Web 服务
猜你喜欢
  • 2016-05-24
  • 2018-07-12
  • 2018-08-31
  • 2021-11-27
  • 2013-03-08
  • 1970-01-01
  • 2017-07-20
相关资源
最近更新 更多