问题描述
我正在使用 spring boot 1.5.1 和 MongoDB 3.4.6 版.
我有一个 mongo 文档 Hotel ,其中包含 Review 列表.
I have a mongo document Hotel which has a list of Review .
Review 类具有属性userName.
@Document public class Hotel { @Id private String id; private List<Review> reviews;
我想通过 Review userName 搜索所有酒店.
I want to search all the hotel by Review userName.
我的 HotelRepository 有 public List
当我与用户Salman"通话时 -
When I am calling with user '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 } ] } ]
我只想要Salman"的评论,但它也为其他人返回.
What I want the reviews only of 'Salman' but it's also returning for others also.
我缺少什么或怎么做?
我注意到,如果单个评论用户匹配它会返回我不想要的评论的整个列表,我想要按名称搜索的评论.
推荐答案
命名查询按原样工作.您并没有明确说您只想要文档的一部分,因此查询返回整个文档.要实现这一点您不能使用命名查询 (请参阅@alexefimov 答案,了解在 @Query 注释的帮助下使用命名查询),但您可以使用
The named query works as it should be. You are not explicitly saying that you want only a portion of document so query returns whole document. To achieve that you cannot use named queries (see @alexefimov answer for using named queries with help of @Query annotation) but you can use MongoTemplatebeside of MongoRepository. to do that you have to make some changes:
首先你的仓库应该是这样的:
First your repository should be like this:
public interface HotelRepository extends MongoRepository<Hotel, String>, MongoTemplateRepository { // You can continue to write your named queries here. Spring will create that. }
MongoTemplateRepository:
MongoTemplateRepository:
public interface MongoTemplateRepository { // You will write your queries which will use mongoTemplate here. List<Hotel> findByReviewsUserName(String userName); }
为了实现 MongoTemplateRepository 方法,您将编写一个新类.重要的是你应该将这个类命名为你的存储库类名+Impl.否则 spring-data 无法找到 MongoTemplateRepository 中定义的方法实现的位置.所以你的实现类的名字应该是 HotelRepositoryImpl
For implementation of MongoTemplateRepository methods, you will write a new class. The important thing here is that you should named this class your repository class name + Impl. Otherwise spring-data cannot find where your methods implementation those defined in MongoTemplateRepository. So your implementation class's name should be 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 字段.当您想包含数组字段的匹配部分时,我们使用 $ 运算符和数组字段名称.
As you can see in codes we can .include() or .excludefields for the query. While you want to include just matched part of an array field, we use $operator with array field name.
结论:您仍然可以使用 spring-data 支持良好的命名查询,此外,如果您需要 聚合 或对无法构建命名查询的子文档进行一些复杂查询到春天,您可以在新创建的 mongoTemplate 存储库类中执行此操作.您可以从 HotelRepository 访问所有存储库方法.
Conclusion: You can still use spring-data well supported named queries and additionally if you need aggregation or some complex queries for sub documents that a named query cannot be built by spring, you can do it in your newly created mongoTemplate repository class. And you can access all of your repository methods from HotelRepository.