Проблема с AccumulatorOperators Max при создании конвейера агрегации

Я пытаюсь преобразовать следующий запрос агрегации оболочки Mongo в агрегацию Spring Data MongoDB:

db.getCollection('Orders').aggregate([
{ $group: {
    "_id": {"book":"$bookingId"},
    "docs": {$push: '$$ROOT'}
  }
},
{$project: {
   latestOrd: {
      $filter: {
         input: "$docs",
         as: "item",
         cond: { $eq: ["$$item.bookingVersion", { $max: "$docs.bookingVersion" }] }
      }
   }
 }
},
{ $unwind: "$latestOrd" },
{ $replaceRoot:{newRoot:"$latestOrd"}}
])

Запрос выбирает все заказы с самой высокой версией бронирования (например, один bookingId может иметь много документов с версией 3).

Этот запрос отлично работает в оболочке Mongo, но у меня проблема с его версией Spring Data:

Aggregation.group("bookingId").push(Aggregation.ROOT).as("docs");
Aggregation.project().and(filter("docs")
          .as("item")
          .by(valueOf("item.bookingVersion")
                .equalToValue(AccumulatorOperators.Max.maxOf("docs.bookingVersion"))))
          .as("latestOrd");
Aggregation.unwind("latestOrd");
Aggregation.replaceRoot("latestOrd");

Spring генерирует запрос Mongo, аналогичный тому, который я предоставил выше, за исключением аккумулятора $ max:

{ "$max" : "$$docs.bookingVersion" }

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

'Use of undefined variable: docs' on server 127.0.0.1:27017

Я использую spring-boot-starter 2.1.0.RELEASE и версию сервера Mongo 4.2. Я ценю любую помощь в этом.

Исходные документы:

[
  {
    "_id": "5f847811ebcd1a51a0196736",
    "status": "REJECTED",
    "bookingId": "1",
    "bookingVersion": 4,
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196735",
    "status": "CREATED",
    "bookingId": "1",
    "bookingVersion": 4,
    "docNumber": "7",
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196734",
    "status": "CREATED",
    "bookingId": "1",
    "bookingVersion": 3,
    "docNumber": "6",
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196738",
    "status": "CREATED",
    "bookingId": "2",
    "bookingVersion": 1,
    "docNumber": "8",
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196737",
    "status": "CREATED",
    "bookingId": "2",
    "bookingVersion": 2,
    "docNumber": "9",
    "operation": "CREATE"
  }
]

Ожидаемый результат:

[
  {
    "_id": "5f847811ebcd1a51a0196736",
    "status": "REJECTED",
    "bookingId": "1",
    "bookingVersion": 4,
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196735",
    "status": "CREATED",
    "bookingId": "1",
    "bookingVersion": 4,
    "docNumber": "7",
    "operation": "CREATE"
  },
  {
    "_id": "5f847811ebcd1a51a0196737",
    "status": "CREATED",
    "bookingId": "2",
    "bookingVersion": 2,
    "docNumber": "9",
    "operation": "CREATE"
  }
]

person Teodor Mysko    schedule 23.12.2020    source источник
comment
Я проверил это с помощью Spring boot starter 2.3.2.RELEASE и mongo версии 4.0.10. Он производит правильный запрос и дает ожидаемый результат. Обновление версии с весенней загрузкой может решить вашу проблему.   -  person Harshit    schedule 24.12.2020
comment
Спасибо @Harshit, но обновление версии с весенней загрузкой для меня не вариант. Я попробую использовать AggregationExpression вместо AccumulatorOperators.Max   -  person Teodor Mysko    schedule 24.12.2020


Ответы (1)


Проблема может быть связана с версией весенней загрузки 2.1.0.RELEASE, но обновление для меня не вариант. Чтобы эта работа работала, я создал AggregationExpression вместо части AccumulatorOperators.Max.maxOf("docs.bookingVersion").

Вот способ для этого:

  private AggregationExpression buildMaxExpression() {
    return new AggregationExpression() {
      @Override
      public Document toDocument(final AggregationOperationContext context) {
        return new Document("$max", "$docs.bookingVersion");
      }
    };
  }
person Teodor Mysko    schedule 24.12.2020