Ошибка несуществующего коммутатора Spring Data MongoDB

#mongodb #spring-data #aggregation-framework #spring-data-mongodb

#mongodb #spring-данные #агрегация-фреймворк #spring-data-mongodb

Вопрос:

Я использую логику объединения для одного из моих сервисов весной, используя MongoDB.

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

 MatchOperation dateMatchOperation = Aggregation.match(
    Criteria.
            where("date").
            gte(new Date(startStamp)).lte(new Date(endStamp)));

MatchOperation propertyMatchOperation = Aggregation.match(
    Criteria.
            where("abc1").is(abcVal1)
            .and("abc2").is(abcVal2)
            .and("abc3").is(abcVal3)
            .and("abc4").is(abcVal4)
            .and("abc5").is(abcVal5)
);

List<Date> dates = new ArrayList<>();
//Create appropriate interval arraylist which will be passed to mongo
for (int i = 0; i < (endStamp - startStamp)/aggregationInterval; i   ) {
dates.add(new Date(startStamp   i * aggregationInterval));
}


BucketOperation bucketOperation = Aggregation.bucket("date").withBoundaries(dates.toArray())
    .andOutput(AccumulatorOperators.Sum.sumOf(aggregationInput)).as("value")
    .andOutput(AccumulatorOperators.Min.minOf("date")).as("from")
    .andOutput(AccumulatorOperators.Max.maxOf("date")).as("to");


AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(true).build();
AggregationResults<MetricAggregationResult> aggregationResults = mongoTemplate.aggregate(
    Aggregation.newAggregation(dateMatchOperation, propertyMatchOperation, bucketOperation)
        .withOptions(aggregationOptions),
    "mongocollectionname",
    MetricAggregationResult.class);

  

Я тестирую это на коллекции с 4,5 миллионами документов. Когда aggregationInterval мал, а в arraylist много элементов, он работает нормально, однако в какой-то момент, постепенно увеличивая интервал агрегации, я заметил, что после некоторой точки агрегации возникает следующая ошибка :

 com.mongodb.MongoCommandException: Command failed with error 40066: '$switch could not find a matching branch for an input, and no default was specified.'
  

Это странно, потому что я не использую агрегации $ switch в своей логике, что касается AggregationOptions, я думал, что агрегация mongo достигла предела в 100 МБ, и я разрешил использование диска.

На данный момент мои руки связаны, я не знаю, что вызывает проблему (я искал по всему StackOverflow ошибку $ switch, но я ничего не мог найти, поскольку все спрашивающие ребята в какой-то степени использовали $ switch в своем коде), но я уверен, что это что-тоэта сторона монго пропускает.

Ответ №1:

 Use BucketAutoOperation

 BucketAutoOperation bucketAutoOperation = Aggregation.bucketAuto("date", 2)
                .andOutput(AccumulatorOperators.Sum.sumOf(aggregationInput)).as("value")
                .andOutput(AccumulatorOperators.Min.minOf("date")).as("from")
                .andOutput(AccumulatorOperators.Max.maxOf("date")).as("to");
  

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

1. От монго [ docs.mongodb.com/manual/reference/operator/aggregation /… : «Классифицирует входящие документы в определенное количество групп, называемых сегментами, на основе указанного выражения. Границы сегментов определяются автоматически в попытке равномерно распределить документы по указанному количеству сегментов.» Это означает, что BucketAuto не является альтернативным для bucket, потому что у него нет возможности предоставлять границы для сегментов, функциональность, которая была обязательной в моем случае.

Ответ №2:

 To use a bucket operation, we specify the following:

groupBy: the field that the boundaries will apply to. This field must be numeric or a date field.
boundaries: an array of boundary points. Documents which have a groupBy field falling between two elements in the array go into that bucket. The between test here is half-open, so the first point is inclusive, second point is exclusive, which is the behavior developers would expect
default: any documents in the pipeline which don’t go into one of the buckets will go into default. This is required. Using a match operation in the pipeline before the bucket operation will remove documents which shouldn’t be processed.
output: an aggregation expression to generate the output document for each bucket


IN the above code, we missed specifying default. 

final BucketOperation bucketOperation = Aggregation.bucket("date").
                withBoundaries(now.minus(10, ChronoUnit.DAYS), now.minus(9, DAYS),
                        now.minus(8, DAYS), now.minus(7, DAYS), now.minus(6, DAYS),
                        now.minus(5, DAYS), now.minus(4, DAYS), now.minus(3, DAYS),
                        now.minus(2, DAYS), now.minus(1, DAYS), now.minus(0, DAYS)).
                withDefaultBucket("defaultBucket").
                andOutput(countingExpression).as("count");
  

Обратитесь к ссылке ниже:-
https://chiralsoftware.com/idea/spring-data-aggregation-operations