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

本文关键字:高计算 计算 文档 驱动程序 mongodb 查找 使用 | 更新日期: 2023-09-27 18:36:49

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

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

使用常规 Linq 的类似内容:

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

有什么建议吗?

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

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

遗憾的是,这无法使用 LINQ 语法来完成。使用规范聚合语法更容易(也更具体),因为它在官方的"聚合管道"文档中有记录。

示例输入:

{ _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 个文档,因为您只需要第一个结果。

我们可以将其转换为JSON并针对我们的数据库执行它:

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;