【问题标题】:Is a MongoDB bulk upsert possible? C# Driver是否可以进行 MongoDB 批量更新? C# 驱动程序
【发布时间】:2017-11-30 22:31:01
【问题描述】:

我想在 Mongo 中进行批量更新插入。基本上我从供应商那里得到了一个对象列表,但我不知道我之前得到了哪些(并且需要更新)以及哪些是新的。我可以逐个进行 upsert,但 UpdateMany 不适用于 upsert 选项。

所以我选择了文档,在 C# 中更新,然后进行批量插入。

    public async Task BulkUpsertData(List<MyObject> newUpsertDatas)
    {
        var usernames = newUpsertDatas.Select(p => p.Username);
        var filter = Builders<MyObject>.Filter.In(p => p.Username, usernames);

        //Find all records that are in the list of newUpsertDatas (these need to be updated)
        var collection = Db.GetCollection<MyObject>("MyCollection");
        var existingDatas = await collection.Find(filter).ToListAsync();

        //loop through all of the new data, 
        foreach (var newUpsertData in newUpsertDatas)
        {
            //and find the matching existing data
            var existingData = existingDatas.FirstOrDefault(p => p.Id == newUpsertData.Id);
            //If there is existing data, preserve the date created (there are other fields I preserve)
            if (existingData == null)
            {
                newUpsertData.DateCreated = DateTime.Now;
            }
            else
            {
                newUpsertData.Id = existingData.Id;
                newUpsertData.DateCreated = existingData.DateCreated;
            }
        }

        await collection.DeleteManyAsync(filter);
        await collection.InsertManyAsync(newUpsertDatas);
    }

有没有更有效的方法来做到这一点?

编辑:

我做了一些速度测试。

在准备过程中,我插入了一个非常简单的对象的 100,000 条记录。然后我将 200,000 条记录插入到集合中。

方法1如问题中所述。 SelectMany,代码更新,DeleteMany,InsertMany。这大约需要 5 秒。

方法 2 使用 Upsert = true 制作 UpdateOneModel 列表,然后执行 BulkWriteAsync。这超级慢。我可以看到 mongo 集合中的计数在增加,所以我知道它正在工作。但大约 5 分钟后,它只攀升到 107,000,所以我取消了它。

如果其他人有潜在的解决方案,我仍然感兴趣

【问题讨论】:

    标签: c# mongodb


    【解决方案1】:

    鉴于您曾说过您可以进行一对一的 upsert,您可以通过 BulkWriteAsync 实现您想要的。这允许您创建抽象 WriteModel 的一个或多个实例,在您的情况下是 UpdateOneModel 的实例。

    为了实现这一点,您可以执行以下操作:

    var listOfUpdateModels = new List<UpdateOneModel<T>>();
    
    // ...
    
    var updateOneModel = new UpdateOneModel<T>(
        Builders<T>.Filter. /* etc. */,
        Builders<T>.Update. /* etc. */)
    {
        IsUpsert = true;
    };
    
    listOfUpdateModels.Add(updateOneModel);
    
    // ...
    
    await mongoCollection.BulkWriteAsync(listOfUpdateModels);
    

    所有这一切的关键是UpdateOneModel 上的IsUpsert 属性。

    【讨论】:

    • 感谢您的回答。这对可能有 600,000 行数据的效率如何?
    • 根据另一个答案,这可能不是您需要担心的事情,因为驱动程序会为您将其分成批次:stackoverflow.com/a/24257439/2630078。话虽如此,您可以通过创建自己的批次并多次调用BulkWriteAsync 等来控制这一点。
    • 抱歉回复太慢了。我有点忙,但想对不同的解决方案进行测试。我发现运行 BulkWriteAsync 对我来说不是一个选项。不过还是谢谢你的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多