Запрос Mongo для фильтрации внутренних элементов Arraylist в Spring Boot с использованием шаблона Mongo - PullRequest
1 голос
/ 07 июля 2019

Ниже мой ДОКУМЕНТ:

@Document(collection = "products")
@Data
@EqualsAndHashCode
public class Product {

    @Id
    private String id;

    @Field("lang_content_list")
    private List<ProductLangContent> contentList;

    @Data
    public static class ProductLangContent {
        @Field("lang")
        private String lang;
    }

}

Я хочу получить только те contentList , где lang = 'en'.lang уникален в списке внутренних.

Примечание: я использую Mongotemplate

Мой пример json:

{
    "_id" : ObjectId("5d2040f9f7c5ac1e9d8ef712"),
    "lang_content_list" : [ 
        {
            "lang" : "en"
        }, 
        {
            "lang" : "np"
        }
    ]
    "_class" : "com.sn.application.model.Product"
}

Желаемый результат запроса:

{
    "_id" : ObjectId("5d2040f9f7c5ac1e9d8ef712"),
    "lang_content_list" : [ 
        {
            "lang" : "en"
        }
    ]
}

Я пробовал пару запросов, но безуспешно:

Aggregation aggregation = newAggregation(
                   project().and(filter("contentList")
                     .as("item")
                     .by(valueOf(
                          "item.lang")
                           .equalToValue(
                          "en")))
                  .as("contentList")
        );
        List<Product> results = mongoTemplate.aggregate(aggregation, Product.class, Product.class).getMappedResults();

вывод: contentList равен null .

Попробовал:

Criteria elementMatchCriteria = Criteria.where("contentList").elemMatch(Criteria.where("lang").is("en"));

Предоставляет все элементы в contentList.Я не хочу этогоЯ хочу только один объект во внутреннем списке, где lan = 'en'.

Огромное Спасибо заранее.

Пробовал:

AggregationOperation match = Aggregation.match(Criteria.where("contentList.lang").is("en"));
        AggregationOperation unwind = Aggregation.unwind("contentList");
        AggregationOperation group = Aggregation.group("id")            
                .push("contentList").as("contentList");

        List<AggregationOperation> operations = new ArrayList<>();
        operations.add(match);
        operations.add(unwind);
        operations.add(match);
        operations.add(group);
        Aggregation aggregation = Aggregation.newAggregation(operations);
        List<Product> results = mongoTemplate.aggregate(aggregation, Product.class, Product.class).getMappedResults();
        System.out.println(results.get(0).getContentList() != null);

вывод: false .Внутренний объект массива возвращается как ноль.

1 Ответ

1 голос
/ 07 июля 2019

В вашем документе есть поле массива "contentList", которое будет иметь несколько "lang".Я предполагаю, что вы хотите отфильтровать / получить все те документы, в которых по крайней мере один "lang" в "contentList" равен "en".Затем используйте:

Criteria elementMatchCriteria = Criteria.where("contentList.lang").is("en"));

Если вы хотите, чтобы во внутреннем массиве был только тот объект, где lang = 'en', вам нужно использовать конвейер агрегации, например:

Ссылка: https://mongoplayground.net/p/JaJ7420i4qJ

db.collection.aggregate([
  {
    $match: {
      "lang_content_list.lang": "en"
    }
  },
  {
    $unwind: "$lang_content_list"
  },
  {
    $match: {
      "lang_content_list.lang": "en"
    }
  },
  {
    $group: {
      "_id": "$_id",
      "_class": {
        $first: "$_class"
      },
      "lang_content_list": {
        $push: "$lang_content_list"
      }
    }
  }
])

Причиной использования последнего группового этапа является то, что в вашем объекте contentList является массивом, поэтому нам нужно обернуть объект lang как массив, в противном случае нет необходимости, если вы можете изменить объект возвращаемого типа.

Весенний код MongoTemplate:

AggregationOperation match = Aggregation.match(Criteria.where("lang_content_list.lang").is("en"));
AggregationOperation unwind = Aggregation.unwind("lang_content_list");
AggregationOperation group = Aggregation.group("_id")             
        .first("_class").as("_class")                
        .push("lang_content_list").as("lang_content_list");

List<AggregationOperation> operations = new ArrayList<>();
operations.add(match);
operations.add(unwind);
operations.add(match);
operations.add(group);
Aggregation aggregation = Aggregation.newAggregation(operations);
List<Product> results = mongoTemplate.aggregate(aggregation, Product.class, Product.class).getMappedResults();
...