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

Posted

技术标签:

【中文标题】使用 Mongo 模板在 Spring Boot 中过滤内部 Arraylist 项的 Mongo 查询【英文标题】:Mongo query to filter inner Arraylist items in Spring Boot using Mongo Template 【发布时间】:2019-11-17 05:21:47 【问题描述】:

以下是我的文件:

@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();

输出为:contentListnull

试过了:

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】:

您的文档有一个数组字段“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"
      
    
  
])

使用最后一个group stage的原因是因为在你的object中,contentList是一个数组,所以我们需要将lang object包装成array,否则如果你可以改变返回类型object就不需要了。

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

【讨论】:

谢谢。但我只想要内部数组中的那个对象,其中 lang='en'。有没有办法过滤掉?我更新了问题以便更好地理解。 仅更新了内部数组中 lang='en' 的对象的答案 抱歉打扰了,你能更新一下我正在使用的语法 MongoTemplate 包的查询吗:org.springframework.data.mongodb.core.MongoTemplate; 嘿,非常感谢。我从您的建议中尝试了一段时间后找到了解决方案。非常感谢。 嗨,@Rajat Goel,你能再帮我一次吗?我在以下链接中发布了问题:***.com/questions/57132939/…

以上是关于使用 Mongo 模板在 Spring Boot 中过滤内部 Arraylist 项的 Mongo 查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot 在 Mongo 中自动扩展

如何使用 Spring Boot 在 Mongo 中存储原始 JSON

Spring Boot使用mongo的GridFS模块

Spring Boot Starter-Web 尝试在启动时连接到 Mongo

Spring boot / mongo 不会使用索引注释创建索引

Dockerize Spring Boot mongo