Mongo 查询以使用 Mongo 模板过滤 Spring 引导中的内部 Arraylist 项

Mongo query to filter inner Arraylist items in Spring Boot using Mongo Template

以下是我的文档:

@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;
    }

}

I want to get only those contentList where lang = 'en'. lang is unique within innner list.

Note: I am using 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();

output is: contentList is null.

尝试过:

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

It gives all elements in contentList. I don't want that. I want only one object in inner list where 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);

output is: false. Inner array object is coming as null.

您的文档有一个数组字段 "contentList",它将有多个 "lang"。我假设您想要 filter/get 所有那些 "contentList" 中至少有一个 "lang" 是 "en" 的文档。然后使用:

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

如果您只想要 lang='en' 的内部数组中的那个对象,您需要使用聚合管道,如:

Link: 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对象包装成数组,否则如果你可以改变return类型对象就不需要。

在Spring 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();