如何在Spring Data MongoDB中保存和查询动态字段? [英] How to save and query dynamic fields in Spring Data MongoDB?

查看:1833
本文介绍了如何在Spring Data MongoDB中保存和查询动态字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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扩展了HashMap< String,Object> {

@Id
private String id;

public String getId(){
return id;
}

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

这样的存储库:

  public interface EntryRepository扩展MongoRepository< Entry,String> {
}

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

 创建名为'entryRepository'的bean时出错:init方法的调用失败;嵌套异常是org.springframework.data.mapping.model.MappingException:无法查找域类java.util.HashMap的映射元数据! 

有什么想法吗?

解决方案

TL; DR;




  1. 不要将Java集合/映射类型用作实体的基类。

  2. 存储库不是满足您需求的正确工具。

  3. 如果您需要动态顶级属性,请使用 DBObject MongoTemplate



解释



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



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

  public interface EntryRepository扩展MongoRepository< Entry,String> {

@Query({?0:?1})
条目findByDynamicField(字符串字段,对象值);
}

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



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

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

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



最后一件事

h2>

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

  @Document 
公共类数据{

@Id
private String id;
私有地图< String,Object>细节;
}


I'm on Spring boot 1.4.x branch and Spring Data MongoDB.

I want to extend a Pojo from HashMap to give it the possibility to save new properties dynamically.

I know I can create a Map<String, Object> properties in the Entry class to save inside it my dynamics values but I don't want to have an inner structure. My goal is to have all fields at the root's entry class to serialize it like that:

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

So I created this Entry class:

@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;
    }
}

And the repository like this:

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

When I launch my app I have this error:

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!

Any idea?

解决方案

TL; DR;

  1. Do not use Java collection/map types as a base class for your entities.
  2. Repositories are not the right tool for your requirement.
  3. Use DBObject with MongoTemplate if you need dynamic top-level properties.

Explanation

Spring Data Repositories are repositories in the DDD sense acting as persistence gateway for your well-defined aggregates. They inspect domain classes to derive the appropriate queries. Spring Data excludes collection and map types from entity analysis, and that's why extending your entity from a Map fails.

Repository query methods for dynamic properties are possible, but it's not the primary use case. You would have to use SpEL queries to express your query:

public interface EntryRepository extends MongoRepository<Entry, String> {

    @Query("{ ?0 : ?1 }")
    Entry findByDynamicField(String field, Object value);
}

This method does not give you any type safety regarding the predicate value and only an ugly alias for a proper, individual query.

Rather use DBObject with MongoTemplate and its query methods directly:

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

DBObject is a Map that gives you full access to properties without enforcing a pre-defined structure. You can create, read, update and delete DBObjects objects via the Template API.

A last thing

You can declare dynamic properties on a nested level using a Map, if your aggregate root declares some static properties:

@Document
public class Data {

    @Id
    private String id;
    private Map<String, Object> details;
}

这篇关于如何在Spring Data MongoDB中保存和查询动态字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆