MongoDB — Возникли трудности с дальнейшей сортировкой результатов запроса

#mongodb #mongodb-query #aggregation-framework

Вопрос:

Это пример коллекции, с которой я работаю

 > db.grades.find().limit(5).forEach(printjson)
{
        "_id" : ObjectId("50b59cd75bed76f46522c353"),
        "student_id" : 0,
        "class_id" : 30,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 14.34345947841966
                },
                {
                        "type" : "quiz",
                        "score" : 47.65945482174327
                },
                {
                        "type" : "homework",
                        "score" : 83.42772189120254
                },
                {
                        "type" : "homework",
                        "score" : 49.86812935368258
                },
                {
                        "type" : "homework",
                        "score" : 39.85525554437086
                }
        ]
}
{
        "_id" : ObjectId("50b59cd75bed76f46522c356"),
        "student_id" : 0,
        "class_id" : 27,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 60.19473636151568
                },
                {
                        "type" : "quiz",
                        "score" : 64.15966210014162
                },
                {
                        "type" : "homework",
                        "score" : 82.80835343023551
                }
        ]
}
{
        "_id" : ObjectId("50b59cd75bed76f46522c350"),
        "student_id" : 0,
        "class_id" : 5,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 88.22950674232497
                },
                {
                        "type" : "quiz",
                        "score" : 79.28962650427184
                },
                {
                        "type" : "homework",
                        "score" : 18.66254946562674
                },
                {
                        "type" : "homework",
                        "score" : 40.28154176513361
                },
                {
                        "type" : "homework",
                        "score" : 1.23735944117882
                },
                {
                        "type" : "homework",
                        "score" : 88.96101200683958
                }
        ]
}
{
        "_id" : ObjectId("50b59cd75bed76f46522c357"),
        "student_id" : 0,
        "class_id" : 11,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 58.83297411100884
                },
                {
                        "type" : "quiz",
                        "score" : 49.66835710930263
                },
                {
                        "type" : "homework",
                        "score" : 18.05861540807023
                },
                {
                        "type" : "homework",
                        "score" : 80.04086698967356
                }
        ]
}
{
        "_id" : ObjectId("50b59cd75bed76f46522c358"),
        "student_id" : 0,
        "class_id" : 10,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 30.93065784731665
                },
                {
                        "type" : "quiz",
                        "score" : 55.98003281528393
                },
                {
                        "type" : "homework",
                        "score" : 55.6752702814148
                },
                {
                        "type" : "homework",
                        "score" : 63.15391302252755
                }
        ]
}
 

Чего я пытаюсь добиться, так это получить наивысший балл на экзамене, где студенческий билет равен 5. Я застрял на этом довольно долго, и самое большее, что мне удалось сделать, — это получить все результаты экзаменов студентов, однако мне не удалось сделать так, чтобы отображался только самый высокий балл. Это еще один аспект, на котором я зациклился.

Это код для этого вывода:

     {
        "student_id" : 5,
        "class_id" : 18,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 73.04238861317688
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 8,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 22.38732080941065
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 0,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 43.64758440439862
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 16,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 33.39752665396672
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 30,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 73.48459944869943
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 19,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 15.36563152024366
                }
        ]
}
{
        "student_id" : 5,
        "class_id" : 23,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 21.58296008740177
                }
        ]
}
 

Код, который дает мне это, выглядит следующим образом:

 var pipeline = [ 
    { $match: {student_id: 5} }, 
    { $unwind: "$scores" }, 
    { $group: { 
    _id: "$_id", 
    "student_id": { "$first": "$student_id" }, 
    "class_id": { "$first": "$class_id" }, 
    scores: { $push: "$scores" } } }, 
    { $project: { _id: 0, 
    student_id: 1, 
    class_id: 1, 
    scores: { $slice: [ "$scores", 1] } } } ];
var results = db.grades.aggregate ( pipeline );
results.forEach(printjson)
 

(Извините за плохую структурированность, я сделал все возможное, но я не слишком привык к этому в stackoverflow)
Я кодирую с MongoDB уже около 2 дней, и я хорошо разбираюсь в этом. Еще меньше с агрегатами, но, глядя на сообщения и другой код, это казалось подходящим способом сделать это. С моей точки зрения, потому что я уже просматриваю его, и попытка отсортировать баллы приведет только к получению наивысшего балла на экзаменах, викторинах и домашних заданиях, так что это не гарантия того, что я сдам экзамен. Если только нет другого способа разобраться в них по отдельности

В идеале я бы хотел, чтобы конечный результат возвращал только один документ, в котором балл экзамена самый высокий:

     {
        "student_id" : 5,
        "class_id" : 30,
        "scores" : [
                {
                        "type" : "exam",
                        "score" : 73.48459944869943
                }
        ]
}
 

Комментарии:

1. итак, вы хотите получить только 1 балл с наивысшими оценками за данный студенческий билет?

2. @sid, да, 1 балл с самыми высокими оценками. Так что в этом случае student_id будет равен 5

Ответ №1:

  • $match student_id состояние
  • $unwind деконструировать scores массив
  • $match type: exam состояние
  • $sort документы score в порядке убывания
  • $group по student_id и получить первый корневой документ
  • $replaceRoot для замены doc на root
 var pipeline = [
  { $match: { student_id: 5 } },
  { $unwind: "$scores" },
  { $match: { "scores.type": "exam" } },
  { $sort: { "scores.score": -1 } },
  {
    $group: {
      _id: "$student_id",
      doc: { $first: "$ROOT" }
    }
  },
  { $replaceRoot: { newRoot: "$doc" } }
]
 

Игровая площадка