如何使用 Spring Data 从 Mongo 中的文档数组字段中仅获取匹配结果

Meh*_*lik 5 java spring-data spring-data-mongodb spring-boot

我正在使用spring boot 1.5.1MongoDB version 3.4.6

我有一个 mongo 文档 Hotel,其中有一个 Review 列表。

Review类有属性userName

@Document
public class Hotel {

    @Id
    private String id;
    private List<Review> reviews;
Run Code Online (Sandbox Code Playgroud)

我想通过评论用户名搜索所有酒店。

我的HotelRepositorypublic List<Hotel> findByReviewsUserName(String userName);

当我与用户“Salman”通话时 -

List<Hotel> list = this.hotelRepository.findByReviewsUserName(user);
Run Code Online (Sandbox Code Playgroud)

此方法返回如下结果:

[
    {
        "id": "59b23c39c70ff63135f76b14",
        "name": "Signature",
        "reviews": [
            {
                "id": 1,
                "userName": "Salman",
                "rating": 8,
                "approved": true
            },
            {
                "id": 2,
                "userName": "Shahrukh",
                "rating": 5,
                "approved": false
            }
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

我只想要“Salman”的评论,但它也会返回给其他人。

我错过了什么或怎么做?

我注意到的是,如果单个评论用户匹配,它会返回我不想要的整个评论列表,我想要按名称搜索的评论。

bar*_*ini 6

命名查询按原样工作。您没有明确说您只需要文档的一部分,因此查询返回整个文档。要实现这一点,您不能使用命名查询 (请参阅@alexefimov 回答以在@Query注释的帮助下使用命名查询),但您可以MongoTemplateMongoRepository. 为此,您必须进行一些更改:

首先你的存储库应该是这样的:

public interface HotelRepository extends MongoRepository<Hotel, String>, MongoTemplateRepository {
    // You can continue to write your named queries here. Spring will create that.
}
Run Code Online (Sandbox Code Playgroud)

MongoTemplateRepository:

public interface MongoTemplateRepository {
    // You will write your queries which will use mongoTemplate here. 
    List<Hotel> findByReviewsUserName(String userName);
}
Run Code Online (Sandbox Code Playgroud)

对于MongoTemplateRepository方法的实现,您将编写一个新类。这里重要的是你应该将这个类命名为你的存储库类名 + Impl。否则 spring-data 无法找到您的方法实现的位置MongoTemplateRepository. 所以你的实现类的名字应该是HotelRepositoryImpl

public class HotelRepositoryImpl implements MongoTemplateRepository {

    @Autowired
    private MongoTemplate mongoTemplate; // we will use this to query mongoDb

    @Override
    public List<Hotel> findByReviewsUserName(String userName) {
        Query query = new Query();
        query.addCriteria(Criteria.where("reviews.username").is(userName));
        query.fields().include("reviews.$");
        return mongoTemplate.find(query, Hotel.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

hotelRepository.findByReviewsUserName("userName");

正如您在代码中看到的那样,我们可以.include().exclude用于查询的字段。虽然您只想包含数组字段的匹配部分,但我们使用$带有数组字段名称的运算符。

结论:您仍然可以使用 spring-data 支持良好的命名查询,此外,如果您需要聚合或对 spring 无法构建命名查询的子文档进行一些复杂的查询,您可以在新创建的 mongoTemplate 存储库类中进行。您可以从HotelRepository.


Ale*_*mov 6

来自@barbakini 的好答案,但这也可以在不使用 Criteria 创建自定义存储库实现的情况下完成,只需“描述”您想要获取的字段,在哪里 0 - .exclude, 1 - .include(

@Query(fields = "{ '_id': 0, 'reviews.$': 1 }")
List<Hotel> findByReviewsUserName(String userName);
Run Code Online (Sandbox Code Playgroud)