Два совокупных итога в одной группе - PullRequest
0 голосов
/ 01 мая 2018

Я написал запрос в MongoDB следующим образом:

db.getCollection('student').aggregate(
[
  {
      $match: { "student_age" : { "$ne" : 15 } }
  },
  {
      $group: 
      {
        _id: "$student_name", 
        count: {$sum: 1},
        sum1: {$sum: "$student_age"}
      }
  }     
])

Другими словами, я хочу получить количество учеников, которым не 15 лет, и краткое изложение их возраста. Запрос работает нормально, и я получаю два элемента данных.

В моем приложении я хочу выполнить запрос по Spring Data . Я написал следующий код:

Criteria where = Criteria.where("AGE").ne(15);
Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(where),
                Aggregation.group().sum("student_age").as("totalAge"),
                count().as("countOfStudentNot15YearsOld"));

Когда этот код запускается, запрос вывода будет:

"aggregate" : "MyDocument", "pipeline" : 
    [           { "$match"   { "AGE" : { "$ne" : 15 } } }, 
                { "$group" : { "_id" : null, "totalAge" : { "$sum" : "$student_age" } } }, 
                { "$count" : "countOfStudentNot15YearsOld" }], 
                  "cursor" : { "batchSize" : 2147483647 } 

К сожалению, результат только countOfStudentNot15YearsOld item.

Я хочу получить результат, как мой собственный запрос.

1 Ответ

0 голосов
/ 02 мая 2018

Если вы просите вернуть группировку для "15" и "не 15" в результате, то вы ищете оператор $cond, который позволит на основе "ветвления" по условной оценке.

Из содержимого оболочки вы можете использовать его следующим образом:

db.getCollection('student').aggregate([
  { "$group": {
    "_id": null,
    "countFiteen": { 
      "$sum": {
        "$cond": [{ "$eq": [ "$student_age", 15 ] }, 1, 0 ]
      }
    },
    "countNotFifteen": {
      "$sum": {
        "$cond": [{ "$ne": [ "$student_age", 15 ] }, 1, 0 ]
      }
    },
     "sumNotFifteen": {
      "$sum": {
        "$cond": [{ "$ne": [ "$student_age", 15 ] }, "$student_age", 0 ]
      }
    }
  }}
])

Таким образом, вы используете $cond для выполнения логического теста, в этом случае, если "student_age" в рассматриваемом текущем документе равно 15 или нет, то вы можете вернуть числовое значение в ответе 1 здесь для «подсчета» или фактического значения поля, когда это то, что вы хотите вместо этого отправить в аккумулятор. Короче говоря, это «троичный» оператор или условие if/then/else (которое на самом деле может быть показано в более выразительной форме с ключами), которое можно использовать для проверки условия и определения того, что возвращать.

Для реализации Spring mongodb вы используете ConditionalOperators.Cond для построения тех же выражений BSON:

import org.springframework.data.mongodb.core.aggregation.*;

ConditionalOperators.Cond isFifteen = ConditionalOperators.when(new Criteria("student_age").is(15))
   .then(1).otherwise(0);

ConditionalOperators.Cond notFifteen = ConditionalOperators.when(new Criteria("student_age").ne(15))
        .then(1).otherwise(0);

ConditionalOperators.Cond sumNotFifteen = ConditionalOperators.when(new Criteria("student_age").ne(15))
        .thenValueOf("student_age").otherwise(0);


GroupOperation groupStage =  Aggregation.group()
        .sum(isFifteen).as("countFifteen")
        .sum(notFifteen).as("countNotFifteen")
        .sum(sumNotFifteen).as("sumNotFifteen");

Aggregation aggregation = Aggregation.newAggregation(groupStage);

Таким образом, вы просто расширяете эту логику, используя .then() для «постоянного» значения, такого как 1 для «счетчиков» и .thenValueOf(), где вам действительно нужно «значение» поля из документ, таким образом, в основном равный "$student_age", как показано для обозначения общей оболочки.

Поскольку ConditionalOperators.Cond совместно использует интерфейс AggregationExpression, это можно использовать с .sum() в форме, которая принимает AggregationExpression вместо строки. Это усовершенствование предыдущих выпусков spring mongo, которое потребовало бы от вас выполнения этапа $project, чтобы существовали фактические свойства документа для вычисленного выражения до выполнения $group .


Если все, что вам нужно, это скопировать исходный запрос для spring mongodb, то ваша ошибка заключалась в использовании этапа агрегации $count вместо добавления к group():

Criteria where = Criteria.where("AGE").ne(15);
Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(where),
                Aggregation.group()
                    .sum("student_age").as("totalAge")
                    .count().as("countOfStudentNot15YearsOld")
);
...