How is an IAsyncCursor used for iteration with the mongodb c# driver?
Short answer: use the ForEachAsync
extension method:
var cursor = await client.ListDatabasesAsync();
await cursor.ForEachAsync(db => Console.WriteLine(db["name"]));
Long answer: Traditional iteration in C# is done with IEnumerable
and foreach
. foreach
is the compiler's syntactic sugar. It's actually a call to GetEnumerator
, a using
scope and a while
loop. But that doesn't support asynchronous operations:
using (var enumerator = enumerable.GetEnumerator())
{
while (enumerator.MoveNext())
{
var current = enumerator.Current;
// use current.
}
}
IAsyncCursor
is equivalent to IEnumerator
(the result of IEnumerable.GetEnumerator
) while IAsyncCursorSource
is toIEnumerable
. The difference is that these support async
(and get a batch each iteration and not just a single item). You can't use foreach
as it's built for IEnumerable
but you can implement the whole using
, while
loop thing:
IAsyncCursorSource<int> cursorSource = null;
using (var asyncCursor = await cursorSource.ToCursorAsync())
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
// use current
}
}
}
However that's a lot of boilerplate so the driver adds extension methods for IAsyncCursor
like ForEachAsync
, ToListAsync
and so forth.
That covers most common use cases but for others you do still need to implement the iteration yourself.
I personally like to convert the cursor into a C# 8 IAsyncEnumerable
, that way you get all the benefits of working with enumerables (LINQ
mainly).
Using @i3arnon's "long answer" I created this extension method:
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IAsyncCursor<T> asyncCursor)
{
while (await asyncCursor.MoveNextAsync())
{
foreach (var current in asyncCursor.Current)
{
yield return current;
}
}
}