在InsertOneAsync()之后,ReplaceOneAsync()并不总是有效,即使在记录时也是如此

时间:2017-11-07 15:02:59

标签: c# mongodb journaling

在单实例MongoDB服务器上,即使客户端上的写入问题设置为已记录,每插入几千个文档中的一个也不能在插入后立即替换。

我的印象是,一旦记录下来,文件立即可用于查询。

下面的代码插入文档,然后更新文档的DateModified属性,并尝试根据文档的ID和该属性的旧值更新文档。

public class MyDocument
{
    public BsonObjectId Id { get; set; }

    public DateTime DateModified { get; set; }
}

static void Main(string[] args)
{
    var r = Task.Run(MainAsync);

    Console.WriteLine("Inserting documents... Press any key to exit.");
    Console.ReadKey(intercept: true);
}

private static async Task MainAsync()
{
    var client = new MongoClient("mongodb://localhost:27017");
    var database = client.GetDatabase("updateInsertedDocuments");

    var concern = new WriteConcern(journal: true);

    var collection = database.GetCollection<MyDocument>("docs").WithWriteConcern(concern);

    int errorCount = 0;
    int totalCount = 0;

    do
    {
        totalCount++;

        // Create and insert the document
        var document = new MyDocument
        {
            DateModified = DateTime.Now,
        };
        await collection.InsertOneAsync(document);

        // Save and update the modified date
        var oldDateModified = document.DateModified;
        document.DateModified = DateTime.Now;

        // Try to update the document by Id and the earlier DateModified
        var result = await collection.ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, document);

        if (result.ModifiedCount == 0)
        {
            Console.WriteLine($"Error {++errorCount}/{totalCount}: doc {document.Id} did not have DateModified {oldDateModified.ToString("yyyy-MM-dd HH:mm:ss.ffffff")}");

            await DoesItExist(collection, document, oldDateModified);
        }
    }
    while (true);
}

代码以每秒约250个文档的速率插入。对ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, ...)的大约1,000-15,000次调用中的一次失败,因为它返回ModifiedCount为0.失败率取决于我们是否运行调试或发布版本以及是否附加调试器:更快的速度意味着更多错误。

显示的代码代表了我无法轻易改变的内容。当然,我宁愿执行一系列Update.Set()来电,但现在还不是一个选项。后跟InsertOneAsync()的{​​{1}}由某种存储库模式抽象,该模式通过引用更新实体。方法的非异步对应方显示相同的行为。

插入和替换之间的简单ReplaceOneAsync()可以缓解问题。

当查询失败,我们等待一段时间,然后尝试在下面的代码中再次查询文档时,每次都会找到它。

Thread.Sleep(100)

发生这种情况的版本:

  • MongoDB社区服务器3.4.0,3.4.1,3.4.3,3.4.4和3.4.10,全部在WiredTiger存储引擎上
  • 服务器在Windows,其他操作系统上运行
  • C#Mongo Driver 2.3.0和2.4.4

这是MongoDB中的一个问题,还是我们正在做(或假设)出错?

或者,实际的最终目标,我如何确保更新可以立即检索插入?

1 个答案:

答案 0 :(得分:3)

如果新文档与旧文档相同,则ReplaceOneAsync返回0(因为没有更改)。

在我看来,如果你的测试执行得足够快,对DateTime.Now的各种调用可以返回相同的值,所以你可能会将完全相同的文档传递给InsertOneAsync和ReplaceOneAsync。