ReplaceOne抛出重复的键异常

时间:2016-09-13 07:38:35

标签: mongodb mongodb-.net-driver

我的应用从远程服务器接收数据,并调用ReplaceOne以使用Upsert = true的给定密钥插入新文件或替换现有文档。 (密钥与*匿名)代码只在单个线程中运行。

但是,有时,应用程序崩溃并出现以下错误:

Unhandled Exception: MongoDB.Driver.MongoWriteException: A write operation resulted in an error.                             
  E11000 duplicate key error collection: ****.orders index: _id_ dup key: { : "****-********-********-************" } ---> MongoDB.Driver.MongoBulkWriteException`1[MongoDB.Bson.BsonDocument]: A bulk write operation resulted in one or more errors.                                                                                                              
  E11000 duplicate key error collection: ****.orders index: _id_ dup key: { : "****-********-********-************" }                                                                                                                  
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)                                                                                                               
   at MongoDB.Driver.MongoCollectionBase`1.ReplaceOne(FilterDefinition`1 filter, TDocument replacement, UpdateOptions options, CancellationToken cancellationToken)                                                                                       
   --- End of inner exception stack trace ---                                                                                
   at MongoDB.Driver.MongoCollectionBase`1.ReplaceOne(FilterDefinition`1 filter, TDocument replacement, UpdateOptions options, CancellationToken cancellationToken)                                                                                       
   at Dashboard.Backend.AccountMonitor.ProcessOrder(OrderField& order)                                                       
   at Dashboard.Backend.AccountMonitor.OnRtnOrder(Object sender, OrderField& order)                                          
   at XAPI.Callback.XApi._OnRtnOrder(IntPtr ptr1, Int32 size1)                                                               
   at XAPI.Callback.XApi.OnRespone(Byte type, IntPtr pApi1, IntPtr pApi2, Double double1, Double double2, IntPtr ptr1, Int32 size1, IntPtr ptr2, Int32 size2, IntPtr ptr3, Int32 size3)                                                                   
Aborted (core dumped) 

我的问题是,当ReplaceOne使用Upsert = true选项时,为什么可以使用重复密钥?

该应用正在以下环境和运行时中运行:

.NET Command Line Tools (1.0.0-preview2-003121)

Product Information:
 Version:            1.0.0-preview2-003121
 Commit SHA-1 hash:  1e9d529bc5

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  16.04
 OS Platform: Linux
 RID:         ubuntu.16.04-x64

MongoDB.Driver 2.3.0-rc1

5 个答案:

答案 0 :(得分:3)

Upsert基于过滤器查询工作。如果过滤查询不匹配,它将尝试插入文档。

如果过滤查询找到文档,它将替换文档。

在你的情况下,它可能以任何一种方式进入,即插入/更新。请检查数据以分析方案。

插入方案: -

如果过滤条件中不存在_id,则会通过upsert自动创建实际的_id。所以,_id不应该创造唯一性问题。如果某些其他字段是唯一索引的一部分,则会产生唯一性问题。

替换方案: -

您尝试更新的字段应该在其上定义唯一索引。请检查集合及其属性的索引。

  

可选。如果为true,则替换以下任一项:(插入文档)   如果没有文档与过滤器匹配,则替换参数。替代对象   将过滤器与替换文档匹配的文档。

     

要避免多次upsert,请确保查询字段是唯一的   索引。

     

默认为false。

     

如果是,MongoDB会将_id字段添加到替换文档中   未在过滤器或替换文档中指定。如果_id是   两者都存在,价值必须相等。

答案 1 :(得分:1)

由于用于过滤器的相同字段上的唯一索引,我无法使IsUpsert = true正常工作,从而导致此错误:E11000 duplicate key error collection重试,如此Jira {{3 }},不是一个很好的解决方法。

未完成的工作似乎是尝试/捕获块,其中包含InsertOne,然后是ReplaceOne,没有任何选择。

try
{
    // insert into MongoDB
    BsonDocument document = BsonDocument.Parse(obj.ToString());
    collection.InsertOne(document);
}
catch
{
    BsonDocument document = BsonDocument.Parse(obj.ToString());
    var filter = Builders<BsonDocument>.Filter.Eq("data.order_no", obj.data.order_no);
    collection.ReplaceOne(filter, document);
}

答案 2 :(得分:0)

您的信息不足,但可能情况如下: 您从服务器接收数据,replaceOne命令不匹配任何记录并尝试插入新记录,但可能您在文档中有一个唯一且已存在于集合中的密钥。在尝试更新或插入数据之前,请检查并对数据进行一些更改。

答案 3 :(得分:0)

我可以共同签署这个:

    public async Task ReplaceOneAsync(T item)
    {
        try
        {
            await _mongoCollection.ReplaceOneAsync(x => x.Id.Equals(item.Id), item, new UpdateOptions { IsUpsert = true });
        }
        catch (MongoWriteException)
        {
            var count = await _mongoCollection.CountAsync(x => x.Id.Equals(item.Id)); // lands here - and count == 1 !!!
        }
    }

答案 4 :(得分:0)

较旧的MongoDB驱动程序存在错误,例如v2.8.1就有此问题。更新您的MongoDB驱动程序,该问题将消失。请注意,当您使用新的驱动程序时,数据库版本也需要更新并兼容。