如何在Spring Data MongoDB中保存和查询动态字段?

时间:2017-09-28 10:12:13

标签: java spring mongodb spring-data

我在Spring boot 1.4.x分支和Spring Data MongoDB上。

我想从HashMap扩展Pojo,以便动态保存新属性。

我知道我可以在Entry类中创建一个Map<String, Object>属性来保存我的动态值,但我不想拥有内部结构。我的目标是让root的入门类中的所有字段按顺序序列化它:

{
   "id":"12334234234",
   "dynamicField1": "dynamicValue1",
   "dynamicField2": "dynamicValue2"
}

所以我创建了这个Entry类:

@Document
public class Entry extends HashMap<String, Object> {

    @Id
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}

这样的存储库:

public interface EntryRepository extends MongoRepository<Entry, String> {
}

当我启动我的应用时出现此错误:

Error creating bean with name 'entryRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.model.MappingException: Could not lookup mapping metadata for domain class java.util.HashMap!

有什么想法吗?

2 个答案:

答案 0 :(得分:10)

TL; DR;

  1. 不要将Java集合/映射类型用作实体的基类。
  2. 存储库不是满足您要求的正确工具。
  3. 如果您需要动态顶级属性,请将DBObjectMongoTemplate一起使用。
  4. 说明

    Spring Data Repositories repositories in the DDD sense充当您明确定义的聚合的持久性网关。他们检查域类以派生适当的查询。 Spring Data从实体分析中排除了集合和地图类型,这就是为什么从Map扩展您的实体失败的原因。

    动态属性的存储库查询方法是可能的,但它不是主要用例。您必须使用SpEL个查询来表达您的查询:

    public interface EntryRepository extends MongoRepository<Entry, String> {
    
        @Query("{ ?0 : ?1 }")
        Entry findByDynamicField(String field, Object value);
    }
    

    此方法不会为您提供有关谓词值的任何类型安全性,也不会为正确的单个查询提供丑陋的别名。

    而是直接使用DBObjectMongoTemplate及其查询方法:

    List<DBObject> result = template.find(new Query(Criteria.where("your_dynamic_field")
                                              .is(theQueryValue)), DBObject.class);
    

    DBObjectMap,可让您完全访问属性,而无需强制执行预定义的结构。您可以通过Template API创建,读取,更新和删除DBObject对象。

    最后一件事

    如果聚合根声明了一些静态属性,则可以使用Map在嵌套级别声明动态属性:

    @Document
    public class Data {
    
        @Id
        private String id;
        private Map<String, Object> details;
    }
    

答案 1 :(得分:2)

这里我们可以实现使用JSONObject

实体将是这样的

@Document
public class Data {
    @Id
    private String id;
    private JSONObject details;
    //getters and setters
}

POJO将是这样的

public class DataDTO {
    private String id;
    private JSONObject details;
        //getters and setters
}

在服务中

Data formData = new Data();
JSONObject details = dataDTO.getDetails();
details.put("dynamicField1", "dynamicValue1");
details.put("dynamicField2", "dynamicValue2");
formData.setDetails(details);
mongoTemplate.save(formData );

我按照我的业务做了,请参考此代码并将其与您的代码相关联。这有用吗?