Почему pymongo генерирует повторяющееся значение _id при использовании insert_one для разных объектов? - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь сохранить объекты в mongodb, используя pymongo. У меня нет проблем с первым объектом, но при попытке сохранить второй объект я получаю pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: km_tracker.entries index: _id_ dup key: { : ObjectId('5b8ce80ebb822e06c8ecf1c7') }

Моя функция сохранения:

def save_entries(entries):
    entries['save_date'] = str(datetime.datetime.now())
    db.entries.insert_one(entries)

След:

Traceback (most recent call last):
  File "app.py", line 182, in <module>
    main();
  File "app.py", line 22, in main
    new_entry()
  File "app.py", line 77, in new_entry
    review_information(entries)
  File "app.py", line 178, in review_information
    save_entries(entries)
  File "app.py", line 93, in save_entries
    db.entries.insert_one(entries)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\collection.py", line 693, in insert_one
    session=session),
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\collection.py", line 607, in _insert
    bypass_doc_val, session)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\collection.py", line 595, in _insert_one
    acknowledged, _insert_command, session)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\mongo_client.py", line 1243, in _retryable_write
    return self._retry_with_session(retryable, func, s, None)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\mongo_client.py", line 1196, in _retry_with_session
    return func(session, sock_info, retryable)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\collection.py", line 592, in _insert_command
    _check_write_command_response(result)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\helpers.py", line 217, in _check_write_command_response
    _raise_last_write_error(write_errors)
  File "C:\Users\someuser\AppData\Local\Programs\Python\Python37\lib\site-packages\pymongo\helpers.py", line 198, in _raise_last_write_error
    raise DuplicateKeyError(error.get("errmsg"), 11000, error)
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: km_tracker.entries index: _id_ dup key: { : ObjectId('5b8ce6adbb822e40d431d444') }

Первый объект, который успешно сохранен в базе данных:

{
"_id" : ObjectId("5b8ce6adbb822e40d431d444"),
"reg_number" : "dfg",
"date" : "dfg",
"b_meter_indication" : "dfg",
"end_meter_indication" : "dfg",
"trip" : "dfg",
"start_address" : "dfg",
"stop_address" : "dfg",
"reason" : "dfg",
"driver" : "dfg",
"other" : "dfg",
"save_date" : "2018-09-03 09:45:49.340871"
}

Второй объект, который не сохраняется из-за дублированного ключа:

{'_id': ObjectId('5b8ce6adbb822e40d431d444'),
 'b_meter_indication': 'rty',
 'date': 'rty',
 'driver': 'rty',
 'end_meter_indication': 'rty',
 'other': 'rty',
 'reason': 'rty',
 'reg_number': 'try',
 'save_date': '2018-09-03 09:46:02.246101',
 'start_address': 'rty',
 'stop_address': 'rty',
 'trip': 'rty'
}

Поскольку я не определяю явно значение _id, но позволяю pymongo сделать это для меня, я не понимаю, почему он присвоит предыдущее значение _id моему текущему объекту. Может ли быть так, что pymongo, по какой-то причине в этом случае, думает, что второй объект такой же, как первый, давая ему то же значение _id?

Python версия: 3.7.0 Mongodb версия 4.0 Версия PyMongo: 3.7.1

Редактировать: добавлены функции с использованием функции save_entries ()

def edit_entry(entries):
    print("Editing: {}".format(entries))
    entry = input()
    return entry

def review_information(entries):
    print("Do you wish to edit something? (y/n)")
    while edit != False or edit != False:
        edit = input()

        if edit == "Y" or edit == "y":
            edit_entry(entries)
        elif edit == "N" or edit == "n":
            break
        else:
            print("Please provide a valid input")
            continue
    save_entries(entries)

1 Ответ

0 голосов
/ 13 сентября 2018

Я не определяю явно значение _id, но позволяю pymongo сделать это для меня

Это связано с тем, что когда документ вставляется в MongoDB с использованием insert_one () , insert_many () или bulk_write () , а этот документ не выполняется включите поле _id, PyMongo автоматически добавит его для вас, установив экземпляр ObjectId.

См. Также FAQ: почему PyMongo добавляет поле _id ко всем моим документам?

У меня нет проблем с первым объектом, но при попытке сохранить второй объект я получаю pymongo.errors.DuplicateKeyError

Вместо явной передачи по значению и передачи по ссылочной семантике, Python передает значение по имени. С Lists и Dicts являются изменяемыми объектами, а Numbers, Strings и Tuples являются неизменяемыми объектами.

В вашем случае, по сути, вы передаете один и тот же объект entries в функцию save_entries(). PyMongo insert_one() изменил объект, добавив поле _id, которое вы попытались сохранить снова. Второе сохранение, однако, уже содержит поле _id, вызывая ошибку дублирования.

Есть несколько способов справиться с этим делом:

  • Явно copy () объект перед передачей в save_entries().
  • Удалять ключ _id из объекта после каждого вызова save_entries(). то есть del entries["_id"].
...