Spring MongoDB: Размер поля проецируемого массива, если он существует - PullRequest
1 голос
/ 20 апреля 2020

В моем документе есть поле Array replies, которое может существовать или не существовать. Если он существует, я хочу вернуть его размер, в противном случае вернуть 0. Ниже мой код проекции. Для документов, которые содержат поле replies с элементами в нем, оно возвращает 0.

 ProjectionOperation project = Aggregation.project("title", "datePosted", "likes").
        and(ConditionalOperators.ifNull(ArrayOperators.arrayOf("replies").length()).then(0)).as("repliesCount");

Чтение ссылки MongoDB do c, это довольно просто, но так или иначе не работает.

Любые предложения приветствуются.

Пример данных

{
"_id" : ObjectId("5e9e3873d022d154c54c2969"),
"title" : "Is this a nice place to meet some interesting people?",
"datePosted" : ISODate("2020-04-21T00:04:03.731Z"),
"views" : 0,
"likes" : 0,
"active" : true
},
{
"_id" : ObjectId("5e9e2f37d022d154c54c2961"),
"title" : "I am posting a quick discussion",
"datePosted" : ISODate("2020-04-20T23:24:39.768Z"),
"views" : 120,
"likes" : 4,
"active" : true,
"replies" : [ 
    {
        "_id" : ObjectId("5e9e2f69d022d154c54c2963"),
        "reply" : "This is the first reply",
        "datePosted" : ISODate("2020-04-20T23:25:29.608Z"),
        "likes" : 0
    },
    {
        "_id" : ObjectId("5e9e2f69d022ad4c54c2964"),
        "reply" : "This is another reply",
        "datePosted" : ISODate("2020-04-20T23:25:29.608Z"),
        "likes" : 0
    }
]
}

Root Причина

Решение предоставлено @valijon правильно. Проблема заключается в POJO DiscussionDoc, в который отображается результат.

@Document(collection = "discussions")
public class DiscussionDoc {

  @Id
  private ObjectId id;

  private String title;
  private LocalDateTime datePosted;
  private int views;
  private int likes;

  @Transient
  private int repliesCount;
  private boolean active;

  @Field(value = "replies")
  private List<ReplyDoc> replyList;
}

Удаление @Transient работает. Я использую @Transient на repliesCount, потому что я не хочу сохранять это поле при сохранении DiscussionDoc. Нет смысла сохранять это поле. Но он будет использоваться для хранения общего количества ответов при извлечении DiscussionDoc. Но @Transient почему-то не позволяет установить repliesCount при получении DiscussionDoc. Я удалил @Transient, чтобы исправить проблему. Но что делать с полем repliesCount, которое теперь сохраняется в БД?

1 Ответ

0 голосов
/ 21 апреля 2020

Вы были почти рядом:

ProjectionOperation project = Aggregation.project("title", "datePosted", "likes").
    and(ArrayOperators.arrayOf(ConditionalOperators.ifNull("replies").then(Collections.emptyList())).length()).as("repliesCount");

Эквивалентно:

{
  "$project": {
    "title": 1,
    "datePosted": 1,
    "likes": 1,
    "repliesCount": {
      "$size": {
        "$ifNull": [
          "$replies",
          []
        ]
      }
    }
  }
}

Обходной путь: Вы можете использовать Gson сериализатор, чтобы получить это расчетное значение:

private static final Gson g = new GsonBuilder().create();
...

List<Document> result = mongoTemplate.aggregate(aggregation, 
    mongoTemplate.getCollectionName(DiscussionDoc.class), Document.class)
        .getMappedResults();

return result.stream()
    .map(doc -> g.fromJson(doc.toJson(), DiscussionDoc.class))
    .collect(Collectors.toList());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...