Улучшите запрос агрегации, чтобы получить отличные результаты

У меня есть этот запрос агрегации, который возвращает объекты Operation с полем amount:BigDecimal выше, чем minAmount, и в пределах диапазона дат. Я хотел бы получить только отдельные результаты (каждый объект Operation имеет operationId:String) на основе operationId.

Я нашел здесь соответствующий пример, но он не помог мне решить мою проблему: отсортированные отдельные значения с помощью MongoTemplate

Я понимаю, что можно использовать addToSet или group, но я не понимаю, как именно включить его в остальную часть запроса.

    private List<OperationDataVO> getInfoFromDB(BigDecimal minAmount,
                                                     Instant startDate, Instant endDate) {
        Criteria criterias = new Criteria()
            .andOperator(Criteria.where(WinningOperation.AMOUNT)
                    .gte(minAmount)
                    .and(Operation.TYPE).is(OperationTypeEnum.WINNING_TYPE)
                    .and("createdAt").gte(startDate).lte(endDate));

        MatchOperation matchOperation = Aggregation.match(criterias);

        ProjectionOperation projectionOperation = 
                Aggregation.project("amount", "operationId");

        Aggregation aggregation = Aggregation.newAggregation(matchOperation,
                projectionOperation, sort(direction, "amount"));

        AggregationResults<OperationDataVO> aggregate = mongoTemplate
                .aggregate(aggregation, COLLECTION, OperationDataVO.class);

        return aggregate.getMappedResults();
    }

Кроме того, я пытался добавить групповую операцию в конвейер Aggregation, но когда я это делаю, я получаю список OperationDataVO, где оба поля каждого объекта null

(Aggregation aggregation = Aggregation.newAggregation(matchOperation, projectionOperation, sort(direction, "amount"), group("operationId")); )


person Community    schedule 23.06.2020    source источник
comment
если есть несколько документов с одним и тем же operationId, какой из них вы хотите вернуть?   -  person herman    schedule 23.06.2020
comment
Тот, у кого самая большая сумма: значение BigDecimal   -  person    schedule 23.06.2020
comment
Итак, вы хотите сгруппировать их по operationId, отсортировать каждую группу по убыванию по amount, а затем получить первую из каждой группы.   -  person herman    schedule 23.06.2020
comment
Я рекомендую сначала создать соответствующий запрос в оболочке mongodb (или эквивалентном инструменте), а затем перевести его в Spring Data Mongo.   -  person herman    schedule 23.06.2020
comment
Что вам нужно в получившемся OperationDataVO? Только amount и operationId? И все отсортировано по возрастанию на amount?   -  person herman    schedule 23.06.2020
comment
Да, мне нужны только эти два поля внутри OperationDataVO   -  person    schedule 23.06.2020
comment
И все отсортировано по количеству   -  person    schedule 23.06.2020


Ответы (1)


Вам нужно отсортировать по убыванию на amount перед группировкой. Группировка должна выполняться с помощью аккумулятора '$first'. Мы сохраняем весь документ, используя $$ROOT. Затем вы можете заменить корневой документ документом из группы.

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

Код оболочки mongo для достижения этой цели будет выглядеть так:

db.getCollection('operationData').aggregate([
{ $match: ... } ,
{ $project: { amount: 1, operationId: 1 } },
{ $sort: { amount: -1 } },
{ $group: { _id: '$operationId', g: { $first: {data: '$$ROOT'} }} },
{ $replaceRoot: { newRoot: '$g.data' }},
{ $sort: { amount: 1 } }
])

Это нужно будет перевести на Spring Data Mongo (возможно, позже у меня будет время попробовать это самому).

person herman    schedule 23.06.2020
comment
Спасибо. Однако использование этого запроса в Studio 3T для MongoDB возвращает только OperationDataVO, полученный объектом Operation с наибольшим значением суммы. - person ; 23.06.2020
comment
Это был $, отсутствующий в идентификаторе операции в группе. - person ; 23.06.2020
comment
На самом деле я просто адаптировал его. - person herman; 23.06.2020
comment
Означает ли g что-то конкретное? - person ; 24.06.2020
comment
@MilanPopescu Я выбрал его как аббревиатуру для группы, но это просто название поля, которое не попадет в окончательный документ, поэтому вы можете выбрать что угодно (но, конечно, адаптируйте обе строки там, где оно используется). - person herman; 24.06.2020