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 string
s). 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?
You have 3 options:
ForEachAsync
, ToListAsync
).IAsyncCursor
into an IAsyncEnumerable
and use await foreach
or any async LINQ operator.IAsyncCursor
.The driver has some LINQ-like extension methods for IAsyncCursor
, like AnyAsync
, ToListAsync
, etc. For iteration it has ForEachAsync
:
var cursor = await client.ListDatabasesAsync(); await cursor.ForEachAsync(db => Console.WriteLine(db["name"]));
IAsyncEnumerable
On C# 8.0 and above it's much nicer to iterate with await foreach
(and use async LINQ). This requires wrapping the IAsyncCursor
in an IAsyncEnumerable
. You can do it yourself but since its important to get some critical things right (like cancellation and disposal) I've published a nuget package: MongoAsyncEnumerableAdapter
var cursor = await client.ListDatabasesAsync(); await foreach (var db in cursor.ToAsyncEnumerable()) { Console.WriteLine(db["name"]); }
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:
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 to IEnumerable
. The difference is that these support async
(and get a batch each iteration and not just a single item). So you can implement the whole using
, while
loop thing yourself:
IAsyncCursorSource<int> cursorSource = null; using (var asyncCursor = await cursorSource.ToCursorAsync()) { while (await asyncCursor.MoveNextAsync()) { foreach (var current in asyncCursor.Current) { // use current } } }
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; } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With