How to do findAll in the new mongo C# driver and make it synchronous
Asked Answered
G

6

27

I was using official C# driver to do a FindAll and upgraded to the new driver 2.0. FindAll is obsolete and is replaced with Find. I am trying to convert a simple method that returns me a list of Class1. Cant find a realistic example using a POCO in their documentation

var collection = database.GetCollection<ClassA>(Collection.MsgContentColName); return collection.FindAll().ToList();

Can someone please help me convert with 2.0 driver and return a list and not a task?

Gaudreau answered 17/4, 2015 at 21:41 Comment(0)
F
-19

you could do this to achieve the same using 2.0 driver,

var collection = database.GetCollection<ClassA>(Collection.MsgContentColName);
var doc = collection.Find(filter).ToListAsync();
doc.Wait();
return doc.Result;
Falchion answered 17/4, 2015 at 21:43 Comment(3)
What is filter? That's not defined or explained anywhere. This does not address the question and contains unexplained/undefined code. The poster wants a FindAll.Hebephrenia
Filter is your FilterDefinition and if you dont have one just use "new BsonDocument()". OP didn't ask for that clarification so thought he figured it out.Falchion
Set filter to "{}", that will return all, although not the best.Reld
W
65

EDIT:

They decided to add back synchronous support (although async is still preferable for IO operations) so you can simply use:

var list = collection.Find(_ => true).ToList();

Original:

Don't block synchronously on asynchronous code. It's bad for performance and could lead to deadlocks.

If you want to keep your application synchronous it's recommended that you keep using the old synchronous driver.

In the new v2.0 driver the async option should look like this:

async Task FooAsync()
{
    var list = await collection.Find(_ => true).ToListAsync();
}
Waver answered 17/4, 2015 at 23:31 Comment(7)
Thanks for the info. However if I return a task wouldn't that propogate to the calling methods as well. I mean, I would have to make all my methods asyc right?Gaudreau
@Gaudreau yes, you would. That's a common result of using async-await. It should rise up as high as possible. Otherwise I would suggest either using the old API (which is still blocking on async requests) or using the latest v1.9 version which is completely synchronous.Waver
"could lead to deadlocks" It shouldn't as MongoDB 2.0 driver uses await by calling ConfigureAwait(false) on Tasks.Elizabethelizabethan
@Elizabethelizabethan It was a general warning. But even for the MongoDB driver, you shouldn't rely on other people's code being bug-free (or your own). That makes your code brittle.Waver
I agree but just wanted to highlight the fact that MongoDB driver does the right thing to prevent you from having a deadlock on cases where you have no other chance but to block (e.g. inside an ASP.NET MVC child action. As you can see, I have a helper to prevent me from having the deadlock as RavenDB client had a bug on that).Elizabethelizabethan
How would I use the above in context.Reld
If you don't want to use async, this works also: var list = collection.Find(_ => true).ToList();Giannagianni
J
2

With the MongoDb version 2.2.4, the implementation changed a little bit. Following the best practices let's build the MongoDb connection like this:

public static class PatientDb
{
    public static IMongoCollection<Patient> Open()
    {
        var client = new MongoClient("mongodb://localhost");
        var db = client.GetDatabase("PatientDb");
        return db.GetCollection<Patient>("Patients");
    } 
}

Now is returned a interface of IMongoCollection instead of instance of a concrete class like MongoCollection. There is no need of create a instance of server to get the database anymore, the client can reach the database directly.

Then in the controller is done like this:

public class PatientController : ApiController
{
    private readonly IMongoCollection<Patient> _patients;

    public PatientController()
    {
        _patients = PatientDb.Open();
    }
    public IEnumerable<Patient> Get()
    {
        return _patients.Find(new BsonDocument()).ToEnumerable();
    }
}

Where _patients is a IMongoCollection and to retrieve all Patients instead to use the FindAll() now is used the Find() where the filter is an new instance of BsonDocument.

Jola answered 28/6, 2016 at 12:43 Comment(0)
H
2

To retrieve all, you can use an empty filter as per the documentation

FilterDefinition<T>.Empty

For example

    public async Task<IEnumerable<ClassA>> GetAllAsync() =>
                await database.GetCollection<ClassA>(Collection.MsgContentColName)
               .Find(FilterDefinition<ClassA>.Empty).ToListAsync();
Haemagglutinate answered 26/6, 2018 at 19:5 Comment(0)
H
1

This is with MongoDb C# Driver 2.2

The new C# driver is asynchronous. Like it or not it should be dealt with. It will come into handy in the future. But for now...

In the code below the asynchronous call is effectively made synchronous because of the code "result.GetAwaiter().GetResult();". This makes the asynchronous code execute to finality in the normal flow.

    static void MongoGoNow()
    {
        IMongoCollection<ClassA> collection = db.GetCollection<ClassA>(Collection.MsgContentColName);
        var result = TestFind(collection);
        result.GetAwaiter().GetResult();
        //What's next???
    }

    static async Task TestFind(IMongoCollection<ClassA> MyCollection)
    {
        var filter = new BsonDocument();
        var count = 0;
        using (var cursor = await MyCollection.FindAsync(filter))
        {
            while (await cursor.MoveNextAsync())
            {
                var batch = cursor.Current;
                foreach (var document in batch)
                {
                    // process document
                    count++;
                }
            }
        }       

You could also merge the last two lines of code in the Main method as follows:

    static void MongoGoNow()
    {
        IMongoCollection<ClassA> collection = db.GetCollection<ClassA>(Collection.MsgContentColName);
        TestFind(collection).GetAwaiter().GetResult();
        //What's next???
    }
Homoiousian answered 12/12, 2015 at 9:0 Comment(0)
W
1

This would be a equivalent to FindAll(),

var list = await collection.Find(new BsonDocument()).ToListAsync();
Wheel answered 11/4, 2019 at 14:1 Comment(0)
F
-19

you could do this to achieve the same using 2.0 driver,

var collection = database.GetCollection<ClassA>(Collection.MsgContentColName);
var doc = collection.Find(filter).ToListAsync();
doc.Wait();
return doc.Result;
Falchion answered 17/4, 2015 at 21:43 Comment(3)
What is filter? That's not defined or explained anywhere. This does not address the question and contains unexplained/undefined code. The poster wants a FindAll.Hebephrenia
Filter is your FilterDefinition and if you dont have one just use "new BsonDocument()". OP didn't ask for that clarification so thought he figured it out.Falchion
Set filter to "{}", that will return all, although not the best.Reld

© 2022 - 2024 — McMap. All rights reserved.