用mongoTemplate在嵌入式文档字段上进行MongoDB

用mongoTemplate在嵌入式文档字段上进行MongoDB

本文介绍了使用mongoTemplate在嵌入式文档字段上进行MongoDB投影的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Java应用程序中,我想检索嵌入式文档的字段.这是我的pojo:

In my java application i want retrieve a field of an embedded document.This is my pojo:

我的User.class

My User.class

public class User implements Comparable<User> {

    @Id
    private String username;

    private String ownerFirstname;

    private String ownerLastname;

    @DBRef
    @CascadeSave
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Role role;
}

Role.class

Role.class

@Document
@JsonDeserialize(using = RoleDeserializer.class)
public interface Role {

    String getId();

    void setId(String id);

}

Society.class

Society.class

@Document(collection = "role")
public class Society implements Role {

    @Id
    private String id;

    private String name;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Address societyAddress;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String vatNumber;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private long birthday;

    private List<ProductResearch> productResearches;

    @DBRef
    private List<Advertisement> advertisementOwnedList;

    @DBRef
    private List<OrderRequest> orderRequests;

    private UserType type;
}

我对adsOwnedList字段感兴趣,但我无法获取它.我尝试使用MongoTemplate进行投影:

I'm interestet to the advertisementOwnedList field but i cannot get it.Using MongoTemplate i have tried to do a projection:

Query query = Query.query(Criteria.where("_id").is(user.getUsername()));
query.fields().include("role.advertisementOwnedList;");
User user1 = mongoTemplate.findOne(query, User.class);

或使用MongoRepository:

Or using MongoRepository:

@Query(value = "{ '_id' : ?0}", fields = "{ '_id': 0 , 'role' : 1 ,
'role.advertisementOwnedList' : 1 }")
User getRoleAdvertisementOwnedList(String username);

但是Role是一个接口,我总​​是会遇到异常:

However Role is an interface and i always get the exception:

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate it.bmv.backend.model.Role using constructor NO_CONSTRUCTOR with arguments

    at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64)
    at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:83)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:259)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:239)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1222)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:85)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1170)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:880)
    at org.springframework.data.mongodb.core.convert.DefaultDbRefResolverCallback.resolve(DefaultDbRefResolverCallback.java:59)
    at org.springframework.data.mongodb.core.convert.DefaultDbRefResolver.resolveDbRef(DefaultDbRefResolver.java:98)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$2.doWithAssociation(MappingMongoConverter.java:313)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:360)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:296)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:239)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:199)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:195)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:85)
    at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:2324)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindOneInternal(MongoTemplate.java:1925)
    at org.springframework.data.mongodb.core.MongoTemplate.doFindOne(MongoTemplate.java:1736)
    at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java:606)
    at org.springframework.data.mongodb.core.MongoTemplate.findOne(MongoTemplate.java:601)
    at it.bmv.backend.UserTest.getAdvTest(UserTest.java:93)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [it.bmv.backend.model.Role]: Specified class is an interface
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:99)
    at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:61)
    ... 50 more

如何获取角色嵌套文档的字段?

How can i get the field of the role nested document?

推荐答案

由于我的评论可能不够清楚,我将尝试给出更详尽的答案.

As my comment wasn't probably clear enough I'll try to give a bit more exhaustive answer.

对于一个内部测试工具,如果有时间我要写,我想出了包含一个或多个不同场景的任务的想法.场景只是需要执行的某个预定义测试.任务还包含一个测试用例列表,其中包含相应测试的当前状态.

For an internal testtool I'm writing if I have time to spare I came up with the idea of tasks that contain one or multiple different scenarios. A scenario is just a certain predefined test that needs to be executed. A task also contains a list of test-cases that contain the current status of a respective test.

我们简化的模型看起来像这样:

Our model simplified looks something like this:

@Getter
@Setter
@Document(collection = "task")
public class TaskEntity implements Serializable, NamedResource {

  @Id
  private String id;
  private String name;
  private String testerName;
  ...
  @DBRef
  private List<ScenarioEntity> testsToExecute = new ArrayList<>();
  ...
  private List<TestCase> performedTests = new ArrayList<>();
  ...
}

场景实体保存在不同的集合中,并且只能在任务条目中用作参考.但是,测试用例是任务中的嵌入式文档.

The scenario entities are maintained in a different collection and only available as reference within the task entry. The test case, however, is an embedded document within the task.

Spring Data允许通过引入一个单独的接口来定义实体或子文档的视图,该接口包含您感兴趣的实体getter方法的子集.

Spring Data allows to define views on entities or sub-documents by introducing a separate interface that contains a subset of the entities getter methods you are interested in.

例如,TaskView包含以下内容:

public interface TaskView extends NamedResource {

  String getTesterName();

  @Value("#{target.testsToExecute}")
  List<ScenarioView> getTestsToExecute();
}

其中ScenarioView看起来像这样:

public interface ScenarioView extends NamedResource {

}

,因为它仅继承了NamedResource中的方法:

as it only inherits the methods from NamedResource:

public interface NamedResource {
  String getId();
  String getName();
}

另一方面,TestCaseView稍微复杂一点,因为它还从包含的条目中检索属性:

The TestCaseView on the other hand is a bit more complex as it also retrieves properties from a contained entry:

public interface TestCaseView {

  String getId();
  String getTaskId();
  Date getStart();
  Date getEnd();
  @Value("#{target.scenario.id}")
  String getScenarioId();
  @Value("#{target.secnario.name}")
  String getScenarioName();
  @Value("#{target.result.result.name()}")
  String getJobResult();
}

为了利用所有这些接口,TaskRepository确实定义了以下查询:

In order to make use of all those interfaces the TaskRepository does define the following queries:

public interface TaskRepository extends MongoRepository<TaskEntity, String> {

  @Query("{ '_id': ?0 }")
  TaskEntity findById(String id);

  @Query("{ }")
  Page<TaskView> findPageable(Pageable pageable);

  @Query("{ '_id': ?0, 'performedTests': { 'id': ?1 } }")
  TestCase findTestCaseByIdViaTaskId(String id, String uuid);

  @Query("{ '_id': ?0, 'performedTests': { } }")
  List<TestCase> findTestsCasesForTask(String id);

  @Query("{ '_id': ?0, 'performedTests': { } }")
  Page<TestCaseView> findTestCaseViews(String id, Pageable pageable);

  ...
}

从代码中可以看到,Spring Data允许直接在存储库接口中定义视图接口,而不是实体类,从而仅检索数据的子集或集合.

As can hopefully be seen from the code, Spring Data allows to define view interfaces directly within the repository interface instead of the entity classes and thus retrieve only a subset or an aggregation of the data.

这篇关于使用mongoTemplate在嵌入式文档字段上进行MongoDB投影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 22:00