Search code examples
c#mongodbaggregation-frameworkmongodb-.net-driver

$map and $filter in a projection on C# - code example


I want to use $map and $filter option of aggregation framework utilizing C# mongodb driver native functions.

Is there any way to do that? If yes can you put some code examples please?

I searched the official documentation of Mongo DB but found nothing.

The following code is in mongo shell script and I want to translate to C# mongodb driver.

var pipeline = 
[
    {
        $match:{
            ExId: {$in: [ObjectId('5d112f91cb865c02b0714d56'), ObjectId("5d168d2c305196e45e73f4a7")]}
        }
    },
    {
        $project:{
            ExId: 1,
            ArrayObject: {
                $map:{
                    'input': '$ArrayObject',
                    'as': 'itemA',
                    'in':{
                        'Name': '$$itemA.Name',
                        'FilterHere': {
                            $filter: {
                                input: '$$itemA.FilterHere',
                                as: 'item',
                                cond: {
                                    $eq: ['$$item.Sent', true]
                                }
                            }
                        }
                    }                        
                }
            }
        }
    }
]

db.getCollection('MyColection').aggregate(pipeline)

I expect the following output into a C# object:

{
    "_id" : ObjectId("5d444527cb865d28e8572d8d"),
    "ExId" : ObjectId("5d112f91cb865c02b0714d56"),
    "ArrayObject" : [ 
        {
            "Name" : 130774,
            "FilterHere" : [ 
                {
                    "Code" : 15900181,
                    "SentDate" : ISODate("2019-08-02T11:13:11.732Z"),
                    "Sent" : true
                }, 
                {
                    "Code" : 15900184,
                    "SentDate" : ISODate("2019-08-02T11:13:11.735Z"),
                    "Sent" : true
                }
            ]
        }
    ]
}

Thanks.


Solution

  • You can find the MongoDB C# Driver Aggregation Documentation here. For constructing an aggregation pipeline in the C# Driver, you have 3 options.

    1. You can use LINQ to aggregate however there aren't always 1:1 mappings between LINQ and the Mongo Query Language.
    2. You can use the driver specific Builder class.
    3. You can use the BsonDocument builders to construct a "raw" aggregation. There is limited, or no type safety using this method.

    The first 2 options require that you create the appropriate classes as the compiler will enforce type safety.

    The "raw" conversion of the aggregation you provided to option 3 is fairly straightforward, albeit a little verbose.

    var foo = new BsonDocument("$project",
    new BsonDocument("ExId", 1).Add("ArrayObject",
        new BsonDocument("$map",
            new BsonDocument("input", "$ArrayObject").Add("as", "itemA").Add("in",
                new BsonDocument("Name", "$$itemA.Name").Add("$filter",
                    new BsonDocument("input", "$$itemA.FilterHere").Add("as", "item").Add("cond",
                        new BsonDocument("$eq", new BsonArray().Add("$$item.Sent").Add(true))))))));
    

    Unfortunately, since I don't know what your input classes look like, it is hard for me to directly translate your pipeline into code. However, looking at the Expressions Documentation, it appears that $map is used for .Select LINQ and $filter is used for .Where LINQ. This would mean, your code looks something like

    col.Aggregate()
    .Match(doc => ids.Contains(doc.ExId))
    .Project(doc => 
        new {
            ExId = doc.ExId,
            ArrayObject = doc.ArrayObject.Select(x =>
                new
                {
                    Name = x.Name,
                    FilterHere = x.FilterHere.Where(y => y.Sent == true)
                })
            });
    

    Since I don't have your actual classes, I could only really guess what they look like, StartObject is my best guess.