1

У меня есть набор документов с 2 Количеством полей, и мне нужно, чтобы отфильтровать все документы, на основе вычисленного условия:Spring Data MongoDB агрегация - соответствие расчетного значения

Number1/Number2 >= CONST% 

Как я могу сделать это возможно с использованием Spring Data Mongo и Aggregation?

--UPDATE--

Я попытался следующий код:

return new RedactAggregationOperation(
      new BasicDBObject(
        "$redact", 
        new BasicDBObject(
          "$cond", new BasicDBObject() 
          .append("if", new BasicDBObject(
            "$gte", Arrays.asList(new BasicDBObject(
            "$divide", 
            Arrays.asList(
              "$Number1", 
              new BasicDBObject(
                "$cond", 
                new BasicDBObject() 
                  .append("$or", Arrays.asList(
                    new BasicDBObject(
                      "$eq", new BasicDBObject(
                      "$Number2", 0)), 
                    new BasicDBObject(
                      "$eq", new BasicDBObject(
                      new BasicDBObject(
                        "$ifNull", 
                        new BasicDBObject(
                          "$Number2", 0)).toString(), 0)))) 
                  .append("then", 1000000) 
                  .append("else", "$Number2")), CONSTANT_VAR)) 
          ))) 
          .append("then", "$$KEEP") 
          .append("else", "$$PRUNE") 
        ) 
      ) 
    ); 

Но есть ошибка «Непризнанный параметр $ конд: $ или» Не могли бы вы помочь с этим вопрос?

+0

'' $ cond "' должен быть массивом, а не '' $ cond ", новый BasicDBObject() .append (" $ или ", Arrays.asList (', заменить эту строку '' $ cond " , Arrays.asList (новый BasicDBObject() .append («$ or», Arrays.asList (' – chridam

+0

@chridam, я думаю, есть также несколько проблем с операторами $ eq. – Tolledo

+0

Да, и это тоже. Там, где есть структура массива, вам нужно использовать соответствующую структуру данных, то есть вместо 'new BasicDBObject()' для массивов, обернуть данные с помощью 'Arrays.asList()'. – chridam

ответ

2

Что вам нужно, это $redact оператор в рамках агрегации, которая позволяет proccess вышеупомянутую логическое условие с оператором в $cond и использует специальные операции $$KEEP «держать» документ, в котором логическое условие true или $$PRUNE «удалить» документ, в котором условие было ложным.

Эта операция аналогична имеющей $project трубопровод, который выбирает поля в коллекции и создает новое поле, который содержит результат логического состояния запроса, а затем последующей $match, за исключением того, что $redact использования который является более эффективным.

Рассмотрим следующий пример, который продемонстрировать выше концепцию:

db.collection.aggregate([ 
    { 
     "$redact": { 
      "$cond": [ 
       { 
        "$gte": [ 
         { "$divide": ["$Number1", "$Number2"] }, 
         CONSTANT_VAR 
        ] 
       }, 
       "$$KEEP", 
       "$$PRUNE" 
      ] 
     } 
    } 
]) 

Поскольку существует no support for the $redact operator yet (на момент написания), обходной путь будет реализовать AggregationOperation интерфейс, который оборачивает операцию агрегации с класс взять в DBObject:

public class RedactAggregationOperation implements AggregationOperation { 
    private DBObject operation; 

    public RedactAggregationOperation (DBObject operation) { 
     this.operation = operation; 
    } 

    @Override 
    public DBObject toDBObject(AggregationOperationContext context) { 
     return context.getMappedObject(operation); 
    } 
} 

, которые затем можно использовать в TypeAggregation:

Aggregation agg = newAggregation(
    new RedactAggregationOperation(
     new BasicDBObject(
      "$redact", 
      new BasicDBObject(
       "$cond", new BasicDBObject() 
        .append("if", new BasicDBObject(
         "$gte", Arrays.asList(
          new BasicDBObject(
           "$divide", Arrays.asList("$Number1", "$Number2") 
          ), 
          CONSTANT_VAR 
         ) 
        ) 
       ) 
       .append("then", "$$KEEP") 
       .append("else", "$$PRUNE") 
      ) 
     ) 
    ) 
); 

AggregationResults<Example> results = mongoTemplate.aggregate(
    (TypedAggregation<Example>) agg, Example.class); 

--UPDATE--

Последующие меры с комментариями, чтобы проверить наличие нулей или нулевых значений на Number2 поле в подразделении, вы бы гнездиться a $cond выражение с логикой вместо.

В следующем примере предполагается, что у вас есть значение замещающий 1, если либо Number2 не существует/равна нулю или имеет нулевое значение:

db.collection.aggregate([ 
    { 
     "$redact": { 
      "$cond": [ 
       { 
        "$gte": [ 
         { 
          "$divide": [ 
           "$Number1", { 
            "$cond": [ 
             { 
              "$or": [ 
               { "$eq": ["$Number2", 0] }, 
               { 
                "$eq": [ 
                 { "$ifNull": ["$Number2", 0] }, 0 
                ] 
               } 
              ] 
             }, 
             1, // placeholder value if Number2 is 0 
             "$Number2"           
            ] 
           } 
          ] 
         }, 
         CONSTANT_VAR 
        ] 
       }, 
       "$$KEEP", 
       "$$PRUNE" 
      ] 
     } 
    } 
]) 

Эквивалент Spring Data Aggregation (непроверенные)

Aggregation agg = newAggregation(
    new RedactAggregationOperation(
     new BasicDBObject(
      "$redact", 
      new BasicDBObject(
       "$cond", Arrays.asList(
        new BasicDBObject(
         "$gte", Arrays.asList(
          new BasicDBObject(
           "$divide", Arrays.asList( 
            "$Number1", 
            new BasicDBObject(
             "$cond", Arrays.asList( 
              new BasicDBObject("$or": Arrays.asList( 
                new BasicDBObject("$eq", Arrays.asList("$Number2", 0)), 
                new BasicDBObject("$eq", Arrays.asList(
                  new BasicDBObject("$ifNull", Arrays.asList("$Number2", 0)), 0 
                 ) 
                ) 
               ) 
              ), 
              1, // placeholder value if Number2 is 0 
              "$Number2"           
             ) 
            ) 
           ) 
          ), 
          CONSTANT_VAR 
         ) 
        ), "$$KEEP", "$$PRUNE" 
       ) 
      ) 
     ) 
    ) 
); 
+0

Можно ли также проверить, является ли Number2 не нулевым (чтобы предотвратить деление на нулевые ошибки)? – Tolledo

+0

Хороший вызов, вам нужно будет добавить другое выражение '$ cond', которое выполняет проверки. Вы собираетесь использовать значение-заполнитель, если «Number2» имеет значение null или имеет нулевое значение? – chridam

+0

Не могли бы вы привести пример в java. Продолжайте получать ошибку "Unrecognized parameter to $ cond: $ или" – Tolledo