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



我正在使用 spring boot 1.5.1MongoDB version 3.4.6

我有一个Mongo Document Hotel,其中有评论清单。

Review类具有属性userName

@Document
public class Hotel {
    @Id
    private String id;
    private List<Review> reviews;

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

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

当我与用户" salman"打电话时 -

List<Hotel> list = this.hotelRepository.findByReviewsUserName(user);

此方法返回结果如下:

[
    {
        "id": "59b23c39c70ff63135f76b14",
        "name": "Signature",
        "reviews": [
            {
                "id": 1,
                "userName": "Salman",
                "rating": 8,
                "approved": true
            },
            {
                "id": 2,
                "userName": "Shahrukh",
                "rating": 5,
                "approved": false
            }
        ]
    }
]

我只想要"萨尔曼"的评论,但它也归还其他人。

我缺少什么或该怎么做?

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

命名查询的工作原理。您没有明确地说您只需要一部分文档,因此查询返回整个文档。为了实现该,您不能使用名为Queries (请参阅@alexefimov的答案,借助@Query注释使用命名查询),但是您可以在MongoRepository旁边使用MongoTemplate。为此,您必须进行一些更改:

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

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

mongotemplaterepository:

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

对于实现MongoTemplateRepository方法,您将编写一个新类。重要的这是您应该命名此类您的存储库类名称 Impl 。否则,弹簧数据将找不到您在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);
    }
}

用法:

hotelRepository.findByReviewsUserName("userName");

您可以在代码中看到,我们可以为查询.include().exclude字段。虽然您要在数组字段中包括仅匹配的部分,但我们将$运算符带有数组字段名称。

结论:您仍然可以使用弹簧数据符合质量的弹簧数据,并在需要 gentregation 或某些复杂的查询(对于无法构建命名查询的sub文档)的情况下。到春季,您可以在新创建的Mongotemplate存储库类中进行。您可以从HotelRepository访问所有存储库方法。

@barbakini的好答案,但这也可以在无需创建具有标准的自定义存储库实现的情况下完成,只是'描述'您想要获得的字段, 0 - .exclude, 1 - .include(

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

最新更新