在单实例MongoDB服务器上,即使客户机上的write concern设置为journaled,每几千个文档中就有一个在插入后不会立即被重放。
我的印象是,一旦记录下来,文档就可以立即进行查询。
下面的代码插入一个文档,然后更新该文档的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个文档的速度插入。大约1000-15000次调用ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, ...)中有一次失败,因为它返回的ModifiedCount值为0。失败率取决于是否运行调试或发布生成,以及是否附加了调试器:速度越快,错误越多。
显示的代码代表了一些我无法轻易更改的内容。当然,我更愿意执行一系列的Update.Set()调用,但这并不是现在真正的选择。InsertOneAsync()后跟ReplaceOneAsync()是由某种通过引用更新实体的存储库模式抽象的。方法的非异步对应项显示相同的行为。
插入和替换之间的简单Thread.Sleep(100)可以缓解问题。
当查询失败时,我们等待一段时间,然后在下面的代码中再次尝试查询文档,每次都会找到它。
private static async Task DoesItExist(IMongoCollection<MyDocument> collection, MyDocument document, DateTime oldDateModified)
{
    Thread.Sleep(500);

    var fromDatabaseCursor = await collection.FindAsync(d => d.Id == document.Id && d.DateModified == oldDateModified);
    var fromDatabaseDoc = await fromDatabaseCursor.FirstOrDefaultAsync();

    if (fromDatabaseDoc != null)
    {
        Console.WriteLine("But it was found!");
    }
    else
    {
        Console.WriteLine("And wasn't found!");
    }
}

发生这种情况的版本:
MongoDB Community Server 3.4.0、3.4.1、3.4.3、3.4.4和3.4.10,均在WiredTiger存储引擎上
服务器运行在windows和其他操作系统上
C Mongo驱动程序2.3.0和2.4.4
这是MongoDB中的问题,还是我们在做(或假设)一些错误的事情?
或者,实际的最终目标是,如何确保通过更新可以立即检索插入?

最佳答案

如果新文档与旧文档相同(因为没有更改),则replaceoneasync返回0。
在我看来,如果您的测试执行速度足够快,那么到目前为止的各种调用都是相同的。现在可以返回相同的值,因此您有可能将完全相同的文档传递给InsertoneAsync和ReplaceOneAsync。

10-08 20:27