Search code examples
c#mongodbmongodb-.net-driver

Can we use multiple nested levels inside a projection with the MongoDB c# driver?


Imagine we have the following classes in c#7, dotnet core 3.1, corresponding to data stored inside a MongoDB collection:

public class Level1
{
    public string Field1 {get; set;}
    public IEnumerable<Level2> Next1 {get; set;}
}

public class Level2
{
    public string Field2 {get; set;}
    public IEnumerable<Level3> Next2 {get; set;}
}

public class Level3
{
    public string Field3 {get; set;}
    public string Field4 {get; set;}
}

For optimization reasons, we want to retrieve Field3 but not Field4, and all the data of Level1 & Level2. (of course this is a simplification: there are a lot of data we actually want to ignore in the real case).

For this, the usual way in Mongo is to use a projection. It works perfectly with JSON queries like find({}, {"Field1": 1, "Next1.Field2": 1, "Next1.Next2.Field3": 1}). We get the full object hierarchy, but with Field4 missing, i.e. exactly what we want.

However, I am stuck when trying to do this in c# using a recent version of the official driver. I could obviously just use the raw JSON query and it would work - but I would miss all the goodness of the driver-managed mapping, such as field names following refactorings. So we want to use expressions.

I have tried this :

var result = db.GetCollection<Level1>("mycollection")
    .Find("{}")
    .Project(Builders<Level1>.Projection.Expression(p => new Level1
    {
        Field1 = p.Field1,
        Next1 = p.Next1.Select(s => new Level2
        {
            Field2 = s.Field2,
            Next2 = s.Next2.Select(r => new Level3
            {
                Field3 = r.Field3,
            },
        },
    }));    

This however generates the following unexpected JSON:

find({}
}, {
    "Field1": 1,
    "Next2.Field3": 1,
    "Next1.Next2": 1,
    "Next1.Field2": 1
})

and of course, this means that Field4 is not filtered - the projection is just wrong. It seems to only work on two levels, and to stop prefixing the projection clauses after two levels.

Would you know if there is a possibility to do what I want with an expression? Thanks!


Solution

  • We have opened a case at MongoDB and they have confirmed it is a bug on their side, referenced on their JIRA

    There is no known workaround using an object expression, so we are using Include() for now and will update when the driver is fixed.