Найдите все встроенные документы из справочника по руководству в MongoDB

Я использую MongoDB и Spring Boot в проекте. Я использовал ручную ссылку, чтобы указать на коллекцию. Моя структура следующая:

Коллекция катушек

{
    _id : "reel_id_1",
    name: "reel 1",
    category :[
        {
            _id : "category_id_1",
            name: "category 1", 
            videos: ["video_id_1","video_id_2"]
        }
    ]
}

Видеоколлекция

{
    _id: "video_id_1",  // first document
    name: "mongo"
}

{
    _id: "video_id_2",  // seconddocument
    name: "java"
}

Классы Java

@Document
@Data
public class Reel {

    @Id
    private ObjectId _id;
    private String name;

    List<Category> category;
}

@Data
public class Category {

    @Id    
    private ObjectId _id=new ObjectId();
    private String name;

    Video videos;
}

@Document
@Data
public class Video {

    @Id
    private ObjectId _id = new ObjectId();
    private String name;
    
}

Я попытался присоединиться к обоим документам через mongoTemplate

public List<Reel> findById(ObjectId _id) {
    LookupOperation lookupOperation = LookupOperation.newLookup()
            .from("video")
            .localField("category.videos")
            .foreignField("_id")
            .as("category.videos");


    UnwindOperation unwindOperation = Aggregation.unwind("category");
    Aggregation agg = newAggregation(unwindOperation,match(Criteria.where("_id").is(_id)),lookupOperation);


    Aggregation aggregation = newAggregation(lookupOperation);
    List<Reel> results = mongoTemplate.aggregate(aggregation, "reel", Reel.class).getMappedResults();
    return results;
}

Но выдает ошибку.

Failed to instantiate java.util.List using constructor NO_CONSTRUCTOR with arguments

Но поскольку я использую размотку, я создал новую сущность UnwindReel и добавил Category category вместо List<Category> category. И использовал

List<UnwindReel> results = mongoTemplate.aggregate(aggregation, "reel", UnwindReel.class).getMappedResults();

Он объединяет только первый объект видео (video_id_1). Как мне получить все объекты внутри массива видео? Есть ли способ получить?


person varman    schedule 11.04.2020    source источник


Ответы (1)


Ваш JSON, хранящийся в базе данных, имеет неправильную структуру. Ваш Reel класс ожидает список Category, но в базе данных вы сохранили как вложенный объект.

Вам нужно добавить этот этап сразу после $lookup

{
  "$addFields": {
    "category": {
      "$map": {
        "input": "$category.videos",
        "in": {
          "videos": "$$this"
        }
      }
    }
  }
}

Код Java

public List<Reel> findById(String _id) {

    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(Criteria.where("_id").is(_id)),
            Aggregation.lookup(mongoTemplate.getCollectionName(Video.class), "category.videos", "_id", "category.videos"),
            new AggregationOperation() {

                @Override
                public Document toDocument(AggregationOperationContext context) {
                    return new Document("$addFields",
                            new Document("category", new Document("$map", new Document("input", "$category.videos")
                                    .append("in", new Document("videos", "$$this")))));
                }
            })
        .withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());

    LOG.debug(
            aggregation.toString().replaceAll("__collection__", mongoTemplate.getCollectionName(Reel.class)));

    return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Reel.class), Reel.class)
            .getMappedResults();

}

Рекомендации

  1. Не жестко кодируйте название коллекции, используйте лучший метод mongoTemplate.getCollectionName
  2. Всегда регистрируйте конвейер агрегирования перед выполнением, это помогает при отладке.
  3. Если ваша коллекция будет расти в будущем, используйте параметр агрегирования {allowDiskUse: true} MongoDb.
person Valijon    schedule 12.04.2020
comment
Слава богу, вы спасли меня, сэр. Я новичок в mongoBD. Но у меня два запроса, вы упомянули, что структура базы данных неправильная. Но я сохранил категорию как массив объектов в Reel.class, могу ли я узнать, что с ней не так? Если я изменю List<Video> вместо Video в коллекции категорий, как я могу изменить указанный выше запрос. - person varman; 12.04.2020
comment
Если я изменю List<Video> вместо Video в коллекции категорий, я бы хотел испортить некоторые дополнительные свойства, такие как catgeory:[ videos:[{_id: "vid_1",upvote:6,downvote: 10 },{_id: "vid_2",upvote:3,downvote: 7 }]]. Как я могу изменить приведенный выше запрос. - person varman; 12.04.2020
comment
@Nishakar, пожалуйста, обновите свой ответ, чтобы я мог добавить образец кода - person Valijon; 12.04.2020
comment
@Valijon, могу ли я узнать, что не так со структурой, как вы упомянули, что помогает мне не реализовывать неправильный дизайн - person varman; 15.04.2020