Spring Boot Data and MongoDB - Filter Subdocument Array Query

前端 未结 1 1893
梦谈多话
梦谈多话 2021-01-14 01:14

I am attempting to use Spring to Query a Mongo repository and filter an array subdocument. I have referenced how to filter array in subdocument with mongodb, but was wonder

相关标签:
1条回答
  • 2021-01-14 01:41

    Well, In Spring Data such kind of queries is not trivial.

    Bad news:
    Spring Data Repository does not have solution for MongoDB Aggregation. So, you cannot implement in MongoRepository any method to do so, like aggregateBy...

    Good news:
    Spring Data provides MongoTemplate class which allows you to execute complex queries, like you would do in standard MongoDB shell.

    So, as you just want to exclude subdocument that does not match some condition, we need to define the aggregate pipelines.

    I assume:

    zip codes are Numeric (In your example is string)
    And, to exclude subdocument, we filter by `zip`
    There is no any other filter
    

    MongoDB aggregation would be:

    db.person.aggregate([
        {$unwind: "$address"},
        {$match: {"address.zip": 12345}},
        {$group: { _id: { "firstName":"$firstName", "lastName":"$lastName", _id:"$_id" }, address: { $push: "$address" } } },
        {$project: {_id:0, "firstName":"$_id.firstName", "lastName":"$_id.lastName", "address": "$address"}}
    ])
    

    If all filters success, we got:

    [ 
        {
            "address" : [ 
                {
                    "zip" : 12345
                }, 
                {
                    "zip" : 12345
                }
            ],
            "firstName" : "George",
            "lastName" : "Washington"
        }
    ]
    


    Now, in Spring Data way, you need add some changes in your project:

    First, find your mongo-config.xml where you need to add:

    <!-- Define the mongoDbFactory with your database Name  -->
    <mongo:db-factory uri="mongodb://user:pass@localhost:27017/db"/>
    
    <!-- Define the MongoTemplate  -->
    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
    </bean>
    

    MongoTemplate is the central class of the Spring’s MongoDB support providing feature sets to interact with the database. The template ... provides a mapping between your domain objects and MongoDB documents. More info

    Second, in your @Service class, add following code to be loaded in @PostConstruct

    @Autowired
    private MongoOperations mongoOperations;
    
    ...
    
    public List<Person> findByAddressZipCode(int zip) {
    
        List<AggregationOperation> list = new ArrayList<AggregationOperation>();
        list.add(Aggregation.unwind("address"));
        list.add(Aggregation.match(Criteria.where("address.zip").is(zip)));
        list.add(Aggregation.group("firstName", "lastName").push("address").as("address"));
        list.add(Aggregation.project("firstName", "lastName", "address"));
        TypedAggregation<Person> agg = Aggregation.newAggregation(Person.class, list);
        return mongoOperations.aggregate(agg, Person.class, Person.class).getMappedResults();
    }
    

    Note: Both, Person and Address should have default empty constructor!

    0 讨论(0)
提交回复
热议问题