简体   繁体   中英

C# MongoDB Take 5 records from every n group

Hello there dear fellow developers,

I'm having trouble with MongoDB C# driver and looking for help.

I am trying to group records by the machineCode column and take 5 record from every column. And also trying to sort all the records descending by the insertDate.

So far i've tried couple threads from SO but failed in all tries.

var list = d3TestCollection
    .AsQueryable<D3TestData>()
    .OrderByDescending(q => q.InsertDate)
    .GroupBy(f => f.machinecode)
    .Select(f => new D3MachineListResult {
        MachineCode = f.Key,
        Values = f.Select(q => new D3KeyValueMap { Key = q.Key, Value = q.Value })
                  .Take(5)
                  .ToList()
    }).ToList();

This code throws Method Not Supported error because of Take(5).

Thank you all.

Example collection:

{
    "_id" : ObjectId("60a607be339f7c44c0d43b70"),
    "key" : "KEY1",
    "machinecode" : "3DTEST1",
    "value" : false,
    "insertDate" : ISODate("2021-05-20T06:54:54.941Z")
},
{
    "_id" : ObjectId("60a607be339f7c44c0d43b70"),
    "key" : "KEY1",
    "machinecode" : "3DTEST2",
    "value" : false,
    "insertDate" : ISODate("2021-05-20T06:54:54.941Z")
},
{
    "_id" : ObjectId("60a607be339f7c44c0d43b70"),
    "key" : "KEY2",
    "machinecode" : "3DTEST3",
    "value" : false,
    "insertDate" : ISODate("2021-05-20T06:54:54.941Z")
},
{
    "_id" : ObjectId("60a607be339f7c44c0d43b70"),
    "key" : "KEY2",
    "machinecode" : "3DTEST4",
    "value" : false,
    "insertDate" : ISODate("2021-05-20T06:54:54.941Z")
}

You have to use aggregate and then group with project. If you need to slice internal array, you have to use Take in projection, not in grouping.

var list = d3TestCollection //IMongoCollection<D3TestData>
        .Aggregate() //IAggregateFluent<D3TestData>
        .SortByDescending(field: x => x.InsertDate)
        .Group(
                id: x => x.machinecode,
                group: x => new D3MachineListResult
                {
                    MachineCode = x.Key,
                    Values = x
                        .Select(z => new D3KeyValueMap
                        {
                            Key = z.Key,
                            Value = z.Value
                        })
                }
            )
        .Project(
            projection: x => new D3MachineListResult
            {
                MachineCode = x.Key,
                Values = x
                    .Select(z => new D3KeyValueMap
                    {
                        Key = z.Key,
                        Value = z.Value
                    })
                    .Take(5)
                
            })
        .ToList();

the aggregation you need is the following:

db.collection.aggregate(
[
    {
        $sort: { insertDate: -1 }
    },
    {
        $group: {
            _id: "$machinecode",
            docs: { $push: "$$ROOT" }
        }
    },
    {
        $project: {
            _id: 0,
            MachineCode: "$_id",
            Values: {
                $map: {
                    input: { $slice: ["$docs", 5] },
                    as: "x",
                    in: {
                        key: "$$x.key",
                        value: "$$x.value"
                    }
                }
            }
        }
    }
])

which cannot be done using the limited LINQ ability of the mongo driver, at least not in a strongly-typed manner.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM