MongoTemplate: группировка по нескольким полям с условием

Ранее у меня был ниже упомянутый конвейер агрегации.

db.EXCEPTIONS.aggregate(
[{ $match : {
        $and : [
            {workflow_stage_current_assignee : {$ne:null}},
            {CreatedDate:{$gt:ISODate("2017-07-12")}}, 
            {CreatedDate:{$lt:ISODate("2018-07-12")}} 
        ]}
 },
 {
     $group : {_id: {user : "$workflow_stage_current_assignee", cm:"$control_monitor"},
               exceptions:{$sum:1} }   
 },
 { $project : {"user":1,"cm":1,"exceptions":1}},
 { $sort : {"exceptions":1}}

]);

И соответствующее преобразование в шаблоне Mongo показано ниже.

Calendar fromDate = Calendar.getInstance();
fromDate.set(2016, 7, 12, 0, 0, 0);

Calendar toDate = Calendar.getInstance();
toDate.set(2018, 7, 12, 23, 59, 59);

MatchOperation match = Aggregation.match(new Criteria("workflow_stage_current_assignee").ne(null)
        .andOperator(new Criteria("CreatedDate").gte(new Date(fromDate.getTimeInMillis()))
        .andOperator(new Criteria("CreatedDate").lte(new Date(toDate.getTimeInMillis())))));

GroupOperation group = Aggregation.group("workflow_stage_current_assignee","control_monitor").count().as("exceptions");

ProjectionOperation project = Aggregation.project("workflow_stage_current_assignee","control_monitor","exceptions");

SortOperation sort=Aggregation.sort(Sort.Direction.DESC,"exceptions");

Aggregation aggregation  = Aggregation.newAggregation(match,group,project,sort);

AggregationResults<ExceptionCount> output  = mongoTemplate.aggregate(aggregation, "EXCEPTIONS", ExceptionCount.class);

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

$group : {_id: {user : "$workflow_stage_current_assignee", cm:"$control_monitor"},
               exceptions:{$sum:1},
               },
               overdue: {$sum : {$cond :[ 
                                    {$gt:["$CreatedDate",ISODate("2017-07-12")]},1,0
                                ]}
               }

Но я не знаю, как добиться этого дополнительного группового предложения в запросах шаблона Mongo. Я искал в Интернете, но большинство результатов используют DBObject из старого API. Может ли кто-нибудь помочь мне в этом с шаблоном Mongo?


person Yogesh Pitale    schedule 15.09.2017    source источник
comment
Возможный дубликат Как выразить сложную группировку $sum выражение в Spring Data MongoDB   -  person s7vr    schedule 29.09.2017
comment
Я чувствую, что задал вопрос до вопроса в приведенной выше ссылке. Так что этот вопрос должен быть дубликатом, а не наоборот! :)   -  person Yogesh Pitale    schedule 03.10.2017
comment
Не уверен, что это за правила. Этот ответ включает в себя последнее обновление, в котором вы можете передать условный оператор как выражение оператору суммы без необходимости дополнительной стадии проекта.   -  person s7vr    schedule 03.10.2017


Ответы (1)


Наконец-то я нашел ответ!

Поскольку я не смог найти способ условно сгруппировать поля с помощью шаблона Mongo, мне пришлось настроить логику самого конвейера агрегации.

  1. Я использовал условную проекцию для проецирования дополнительного поля.
  2. Сначала выполняется операция проецирования.
  3. Затем выполняется группировка по этому дополнительному полю.

Итак, требуемые изменения кода приведены ниже.

Шаг 1

Я изменил предложение проекции и добавил еще одно поле условной проекции, как показано ниже.

Cond overdueCondition = ConditionalOperators.when(new Criteria("CreatedDate").gt(new Date())).then(1).otherwise(0);
ProjectionOperation project = Aggregation.project("workflow_stage_current_assignee","control_monitor","exceptions").and("overdue").applyCondition(overdueCondition);

Результат этой операции уменьшит мой результирующий набор примерно до такого:

{
"workflow_stage_current_assignee" : "Yogesh",
"control_monitor" : "P005",
"exceptions":"",
"overdue" : 1
},
{
"workflow_stage_current_assignee" : "Yogesh",
"control_monitor" : "P005",
"exceptions":"",
"overdue" : 0
}...

После шага 1 я получил еще одно поле в проекции, называемое просроченным, со значением 1 или 0 в зависимости от того, выполнено ли мое условие или нет.

Шаг 2

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

GroupOperation group =  Aggregation.group("workflow_stage_current_assignee","control_monitor").count().as("exceptions").sum("overdue").as("overdue");

Шаг 3

И, наконец, я изменил свой конвейер агрегации, чтобы сначала выполнить операцию Projection, а затем сгруппировать все результаты.

Aggregation aggregation  = Aggregation.newAggregation(match,project,group,sort);

Это дало мне требуемые результаты!

person Yogesh Pitale    schedule 21.09.2017