How is an IAsyncCursor used for iteration with the mongodb c# driver?

Shamster picture Shamster · Apr 16, 2015 · Viewed 14.7k times · Source

I'm trying to get a list of all the databases in my server and ultimately print them out (i.e. use their names as strings). With the previous version of the c# driver I could call the Server.GetDatabases(), but that has been replaced with ListDatabasesAsync().

The return value is an IAsyncCursor<> and I'm not sure what to do with it. How does one iterate through the list of databases (or anything) with such a cursor?

Answer

i3arnon picture i3arnon · Apr 16, 2015

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.