Mongo查询使用Mongo模板在Spring Boot中过滤内部Arraylist项目

时间:2019-07-07 12:48:23

标签: mongodb spring-boot mongotemplate

以下是我的文档:

@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

尝试:

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 。内部数组对象为null。

1 个答案:

答案 0 :(得分:1)

您的文档具有一个数组字段“ contentList”,该字段将具有多个“ lang”。我假设您要过滤/获取“ contentList”中至少一个“ lang”为“ 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();