如何 运行 对游标的最终迭代进行编码

How to run code on final iteration on a cursor

我有一个存储库函数 GetDocs(),returns 一个 MongoDB 游标。

在我调用 GetDocs 的地方,我遍历光标并在每五次迭代时调用 SetLastId()

问题:如何识别何时处理游标的最后一个元素,以便在退出前调用SetLastId()循环?

public async Task GetDocs(string id, Func<Model, Task> processor)
        {
            var filter = Builders<Model>.Filter;
            var sort = Builders<Model>.Sort;
            using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
            {
                foreach (var doc in cursor.Current)
                {                    
                    await processor(doc);
                }
            }
        }

.

    using (OdbcConnection conn = new OdbcConnection(context.connectionString))
    {
        conn.Open();
        int counter = 0;

        await repo.GetDocs(context.Id, async (doc) =>
         {
             if (counter % 5 == 0)
             {
                var success = await SetLastId(doc.Id);
             }
             counter++;
         });
    }

像这样的事情怎么样?基本上,循环会将之前的文档存储在内存中,并在下一次迭代中处理它。这样,一旦它退出循环,它就会得到 "last doc" 并可以将其标记为处理器。

public async Task GetDocs(string id, Func<Model, bool, Task> processor)
{
    var filter = Builders<Model>.Filter;
    var sort = Builders<Model>.Sort;
    using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
    {
        Model previousDoc = null;
        foreach (var doc in cursor.Current)
        {
            if (previousDoc != null)
            {
                await processor(previousDoc, false);
            }
            previousDoc = doc;
        }
        if (previousDoc != null)
        {
            await processor(previousDoc, true);
        }
    }
}

您也可以将它包装成一个可与任何 IEnumerable 一起使用的可重用方法(我在这里使用了 ValueTuples,但如果您不能使用它们,您可以创建自己的类型):

public static IEnumerable<(T Model, bool IsLast)> Map<T>(IEnumerable<T> items)
{
    T prevModel = default(T);
    bool isFirst = true;
    foreach (var model in items)
    {
        if (!isFirst)
        {
            yield return (prevModel, false);
        }
        else
        {
            isFirst = false;
        }
        prevModel = model;
    }

    if (!isFirst)
    {
        yield return (prevModel, true);
    }
}


public async Task GetDocs(string id, Func<Model, bool, Task> processor)
{
    var filter = Builders<Model>.Filter;
    var sort = Builders<Model>.Sort;
    using (var cursor = await Coll.Find(filter.Eq(f => f.id, id)).ToCursorAsync())
    {
        foreach (var docWrapper in Map(cursor.Current))
        {
            await processor(docWrapper.Model, docWrapper.IsLast);
        }
    }
}