使用c#驱动程序在mongodb中查找具有最高计算值的文档

时间:2015-01-08 15:12:47

标签: c# .net mongodb mongodb-query mongodb-.net-driver

有没有办法找到mongo db中具有最高计算值的文档?

我有一个数组属性,由int的1-5组成。我想找到平均值最高的文档。

使用常规Linq这样的东西:

var entityWithCalculatedMax = collection.OrderByDescending(x => x.Grade.Sum() / x.Grade.Count()).First();    

有什么建议吗?

(我试图直接在数据库中执行此操作,因为我不想检索所有文档以获取文档)

1 个答案:

答案 0 :(得分:4)

不幸的是,使用LINQ语法无法做到这一点。使用正则聚合语法更容易(也更具体),如the official "Aggregation Pipeline" documentation中所述。

示例输入:

{ _id: 1, Grades: [ 1, 1 ] }
{ _id: 2, Grades: [ 2, 3, 4 ] }
{ _id: 3, Grades: [ 5 ] }

想法是在聚合管道中有四个步骤:

  1. 展开每个Grades数组:对于每个文档,这将创建 n 文档,其中 n 是数字每个文件具有单一成绩的成绩:

    结果:

    { _id: 1, Grades: 1 }
    { _id: 1, Grades: 1 }
    { _id: 2, Grades: 2 }
    { _id: 2, Grades: 3 }
    { _id: 2, Grades: 4 }
    { _id: 3, Grades: 5 }
    
  2. 按ID分组文件,汇总a)平均属性(您的计算)和b)新的Grades属性以恢复我们的数组:

    结果:

    { _id: 1, Average: 1.0, Grades: [ 1, 1 ] }
    { _id: 2, Average: 3.0, Grades: [ 2, 3, 4 ] }
    { _id: 3, Average: 5.0, Grades: [ 5 ] }
    
  3. 按平均值排序文档。

    结果:与上述相同,因为它已经以某种方式订购。

  4. 限制为1个文档,因为您只需要第一个结果。

  5. 我们可以将其转换为JSON并对我们的db执行它:

    db.gradeDocs.aggregate(
        [
            { $unwind: "$Grades" },
            { 
                $group: {
                    _id: "$_id",
                    Average: { $avg: "$Grades" },
                    Grades: { $push: "$Grades" }
                }
            },
            { $sort: { "Average": 1 } },
            { $limit: 1 }
        ]
    )
    

    好的,现在我们如何使用C#驱动程序执行此操作?语法有点冗长,但基本上它是一样的:

    var aggregateArgs = new AggregateArgs();
    aggregateArgs.Pipeline =
        new[]
        {
            new BsonDocument("$unwind", "$Grades"), 
            new BsonDocument("$group", 
                new BsonDocument
                {
                    {"_id", "$_id"},
                    {"Average", new BsonDocument("$avg", "$Grades")},
                    {"Grades", new BsonDocument("$push", "$Grades")},
                }),
            new BsonDocument("$sort", new BsonDocument("Average", 1)), 
            new BsonDocument("$limit", 1), 
        };
    
    var resultId = collection
        .Aggregate(aggregateArgs)
        .Single()["_id"]
        .AsObjectId;