Search code examples
c#mongodbprojection

MongoDB C# projection query without magic strings like "{ MyProperty : 1 }"


if I want to read/return only one property of a complex object/document in MongoDb c#. I use this methode:

public List<T> ReadAllReturnOnlyOneProp<T>(string collection, string nameOfFieldToRead)
{
     var _collection = db.GetCollection<T>(collection);
     return _collection.Find(new BsonDocument()).Project<T>(nameOfFieldToRead).ToList();
}

To call this I need to use:

var test = myMongoAux.ReadAllReturnOnlyOneProp<MyTModel>(myCollectionName, "{MyDBString: 1}");

The part "{MyDBString: 1}" signals that I only want this one property returned from the complex documents. 'MyDBString' would be a property of the object/document (the :1 => return true).

I dont like that I do have to use this hardcoded string. I am more used to do something like ..., nameof(MyClass.MyDBString)

Is this a workaround if I rewrite my methode?:

public List<T> ReadAllReturnOnlyOneProp<T>(string collection, string nameOfFieldToRead)
{
     var magicString = "{" + nameOfFieldToRead + ":"+"1"+ "}"; 
     var _collection = db.GetCollection<T>(collection);
     return _collection.Find(new BsonDocument()).Project<T(magicString).ToList();
}

with this call:

var test = myMongoAux.ReadAllReturnOnlyOneProp<MyTModel>(myCollectionName, nameof(MyTModel.MyDBString));

Or is this the solution?


Solution

  • you can change the method to the following and use a member expression to specify the property you want to get back:

    public List<T> ReadAllReturnOnlyOneProp<T>(string collection, Expression<Func<T, object>> projection)
    {
        var _collection = db.GetCollection<T>(collection);
    
        return _collection
            .Find(_ => true)
            .Project<T>(Builders<T>.Projection.Include(projection))
            .ToList();
    }
    

    call the method like this:

    var result = ReadAllReturnOnlyOneProp<MyTModel>(myCollectionName, x => x.MyDBString);
    

    also recommend you to switch to async/await model and stop using the official driver's legacy sync-over-async api like you're using here. see this page for the reason.