如何使用 Spring 数据从 Mongo 文档的数组字段中仅获取匹配结果
How to Get Only Matched Result from An Array Field of Document in Mongo Using Spring Data
我正在使用 spring boot 1.5.1
和 MongoDB version 3.4.6
.
我有一份 mongo 文档酒店,其中包含评论列表。
Review
class 有 属性 userName
.
@Document
public class Hotel {
@Id
private String id;
private List<Review> reviews;
我想通过评论用户名搜索所有酒店。
我的 HotelRepository
有 public List<Hotel> findByReviewsUserName(String userName);
当我与用户通话时 'Salman' -
List<Hotel> list = this.hotelRepository.findByReviewsUserName(user);
此方法 returns 结果如下:
[
{
"id": "59b23c39c70ff63135f76b14",
"name": "Signature",
"reviews": [
{
"id": 1,
"userName": "Salman",
"rating": 8,
"approved": true
},
{
"id": 2,
"userName": "Shahrukh",
"rating": 5,
"approved": false
}
]
}
]
我只想要 'Salman' 的评论,但它也会为其他人返回。
我缺少什么或如何做?
我注意到,如果一个评论用户匹配它 returns 我不想要的整个评论列表,我想要我按名称搜索过的评论。
命名查询正常工作。您没有明确表示您只需要文档的一部分,因此查询 returns 整个文档。要实现这一点,你不能使用命名查询 (参见@alexefimov answer for using named queries with help of @Query
annotation) 但你可以在 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
方法,您将编写一个新的class。 这里重要的 是您应该将此命名为 class 您的存储库 class 名称 + Impl。否则 spring-data 无法找到您在 MongoTemplateRepository
中定义的方法实现的位置。所以你的实现 class 的名字应该是 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
字段进行查询。当您只想包含数组字段的匹配部分时,我们使用 $
运算符和数组字段名称。
结论:你仍然可以使用spring-数据支持的命名查询,另外如果你需要聚合或一些spring 无法构建命名查询的子文档的复杂查询,您可以在新创建的 mongoTemplate 存储库 class 中完成。您可以从 HotelRepository
.
访问所有存储库方法
来自@barbakini 的好答案,但也可以在不使用 Criteria 创建自定义存储库实现的情况下完成,只需 'describe' 您想要获得的字段,其中 0 - .exclude, 1 - .include(
@Query(fields = "{ '_id': 0, 'reviews.$': 1 }")
List<Hotel> findByReviewsUserName(String userName);
我正在使用 spring boot 1.5.1
和 MongoDB version 3.4.6
.
我有一份 mongo 文档酒店,其中包含评论列表。
Review
class 有 属性 userName
.
@Document
public class Hotel {
@Id
private String id;
private List<Review> reviews;
我想通过评论用户名搜索所有酒店。
我的 HotelRepository
有 public List<Hotel> findByReviewsUserName(String userName);
当我与用户通话时 'Salman' -
List<Hotel> list = this.hotelRepository.findByReviewsUserName(user);
此方法 returns 结果如下:
[
{
"id": "59b23c39c70ff63135f76b14",
"name": "Signature",
"reviews": [
{
"id": 1,
"userName": "Salman",
"rating": 8,
"approved": true
},
{
"id": 2,
"userName": "Shahrukh",
"rating": 5,
"approved": false
}
]
}
]
我只想要 'Salman' 的评论,但它也会为其他人返回。
我缺少什么或如何做?
我注意到,如果一个评论用户匹配它 returns 我不想要的整个评论列表,我想要我按名称搜索过的评论。
命名查询正常工作。您没有明确表示您只需要文档的一部分,因此查询 returns 整个文档。要实现这一点,你不能使用命名查询 (参见@alexefimov answer for using named queries with help of @Query
annotation) 但你可以在 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
方法,您将编写一个新的class。 这里重要的 是您应该将此命名为 class 您的存储库 class 名称 + Impl。否则 spring-data 无法找到您在 MongoTemplateRepository
中定义的方法实现的位置。所以你的实现 class 的名字应该是 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
字段进行查询。当您只想包含数组字段的匹配部分时,我们使用 $
运算符和数组字段名称。
结论:你仍然可以使用spring-数据支持的命名查询,另外如果你需要聚合或一些spring 无法构建命名查询的子文档的复杂查询,您可以在新创建的 mongoTemplate 存储库 class 中完成。您可以从 HotelRepository
.
来自@barbakini 的好答案,但也可以在不使用 Criteria 创建自定义存储库实现的情况下完成,只需 'describe' 您想要获得的字段,其中 0 - .exclude, 1 - .include(
@Query(fields = "{ '_id': 0, 'reviews.$': 1 }")
List<Hotel> findByReviewsUserName(String userName);