当对不同对象使用insert_one时,为什么pymongo会生成重复的_id值?

时间:2018-09-05 13:51:35

标签: python mongodb pymongo

我正在尝试使用pymongo将对象保存到mongodb。我的第一个对象没有问题,但是当尝试保存第二个对象时,我得到了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)

2 个答案:

答案 0 :(得分:1)

我也有同样的问题,但是现在我解决了。

就我而言,我在for循环中创建了一个新字典。首先在循环判断条件下,如果日期是我所需要的,我将insert_one制作到MongoDB数据库,但是Pymongo认为即使文件中的内容完全不同,它也是同一个对象,因为dict具有相同的内存ID,所以它没有。 t创建一个新的“ _id”。所以我需要将dict从循环位置放到if位置。

for itemin items:
i = 1
while i < len(item['a']):
    if (item['a'][i-1]['date'] < item['a'][i]['date']:
        temp= {}     #this one
        ...
        db.collection.insert_one(temp)
    i +=1

答案 1 :(得分:0)

  

我没有明确定义_id的值,而是让pymongo为我完成此操作

这是因为,当使用insert_one()insert_many()bulk_write()将文档插入到MongoDB中时,该文档不包含_id字段,{{3 }}会自动为您添加一个,并设置为ObjectId的实例。

另请参阅PyMongo

  

第一个对象没有问题,但是尝试保存第二个对象时出现pymongo.errors.DuplicateKeyError

Python并没有按值显式传递和按引用语义传递,而是按名称传递值。列表和字典是可变对象,数字,字符串和元组是不可变对象。

在您的情况下,实际上是将相同的entries对象传递给save_entries()函数。 PyMongo insert_one()通过添加_id字段修改了对象,然后您尝试再次保存。但是,第二次保存已经包含_id字段,从而导致重复错误。

处理这种情况的方法很少: