Агрегация и конвейер

  • Фреймворк агрегации позволяет обработать большое число документов в несколько стадий (запросов).
  • Последовательность из нескольких стадий называется конвейером.

Запуск

mCourses.aggregate<Course>(
  match(Course::name eq "Math"),
)

{"result": [{
    "name": "Math",
    "grades": [
        {   "studentId": {"$oid": "643389b943f49536198c83e4"},
            "date": 1681099194567,
            "studentName": "Penny",
            "value": 5 },
        { "studentId": {"$oid": "643389b943f49536198c83e5"},
            "date": 1681099194567,
            "studentName": "Amy",
            "value": 5 },
        ...
    ]
}]}

Разворачивание

@Serializable
class UnwindCourse(
  val name: String,
  val grades: Grade
)
@Serializable
data class Course(
  val name: String,
  val grades: List<Grade> = emptyList()
)
mCourses.aggregate<UnwindCourse>(
  unwind("\$grades")
)

Разворачивание. Результат

{"result": [
  { "name": "Math",
    "grades": { "studentId": {"$oid": "..."},
      "date":1681099194567, "studentName":"Penny", "value":5 }},
  { "name": "Math",
    "grades": { "studentId": {"$oid": "..."},
      "date":1681099194567, "studentName":"Amy", "value":5 }},
  ...    
  { "name": "Phys",
    "grades": { "studentId": {"$oid": "..."},
      "date":1681099194568, "studentName":"Penny", "value":4 }},
  ...
]}

Применение разворачивания

mCourses.aggregate<UnwindCourse>(
  unwind("\$grades"),
  match(UnwindCourse::grades / Grade::studentName eq "Penny")
)

{"result": [
  { "name": "Math",
    "grades": {"studentId": {"$oid": "..."},
    "date":1681099194567, "studentName":"Penny", "value":5 }},
  { "name": "Phys",
    "grades": {"studentId": {"$oid": "..."},
    "date": 1681099194568, "studentName":"Penny", "value":4 }},
  { "name": "History",
    "grades": {"studentId": {"$oid": "..."},
    "date": 1681099194568, "studentName":"Penny", "value":5 }}
]}

Проекция. Цель

@Serializable
data class StudentGrade(
  val value: Int? = null,
  @Serializable(with = DateAsLongSerializer::class)
  val date: Date? = null,
)
@Serializable
data class UnwindStudentCourse(
  val name: String,
  val grades: StudentGrade
)

Проекция. Результат

mCourses.aggregate<UnwindStudentCourse>(
  unwind("\$grades"),
  match(UnwindCourse::grades / Grade::studentName eq "Penny"),
  project(
    UnwindCourse::name,
    UnwindCourse::grades / Grade::value,
    UnwindCourse::grades / Grade::date ) ) 

{"result": [
{ "name": "Math",
  "grades": {
    "date": 1681099194567,
    "value": 5 }},
{ "name": "Phys",
  "grades": {
    "date": 1681099194568,
    "value": 4 } },
{ "name": "History",
  "grades": {
    "date": 1681099194568,
    "value": 5 } } ] }

Дополнительные функции

mCourses.aggregate<UnwindStudentCourse>(
  unwind("\$grades"),
  match(UnwindCourse::grades / Grade::studentName eq "Penny"),
  project(...),
  sort(UnwindStudentCourse::grades / StudentGrade::value eq 1),
  limit(2) )

{"result": [
  { "name": "Phys",
    "grades": {
      "date": 1681099194568,
      "value": 4 } },
  { "name": "Math",
    "grades": {
      "date": 1681099194567,
      "value": 5 } } ]}

Функции агрегирования

@Serializable data class Result(
  val _id: String, val grades: Int)
mCourses.aggregate<Result>(
  unwind("\$grades"),
  group( UnwindCourse::grades / Grade::studentName,
    Result::grades sum UnwindCourse::grades / Grade::value ) ) 

{"result": [
  { "_id": "Sheldon",
    "grades": 15 },
  { "_id": "Leonard",
    "grades": 12 },
  { "_id": "Howard",
    "grades": 11 }, 
  ...
]}