使用Spring将JSON模式存储到MongoDB

10

我是Spring Data和MongoDB的新手。我有一个JSON对象,表示一个JSON模式,我需要使用Spring Data将其存储在MongoDB中。但是JSON模式的问题在于,JSON模式的结构是动态的;例如,以下是两个具有完全不同结构的有效JSON模式。

{
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "minLength": 10
        },
        "age": {
            "type": "integer"
        }
    },
    "required": [
        "name",
        "age"
    ]
}

{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "abc": {
                "type": "boolean"
            },
            "xyz": {
                "$ref": "#/definitions/"
            },
            "asd": {
                "type": "null"
            }
        },
        "required": [
            "abc",
            "xyz"
        ]
    }
}

如何定义一个JAVA POJO类,使其能够将上述JSON映射到定义的类并存储在mongodb中。或者是否可能在Spring中执行CURD操作而不将其映射到POJO类?

5个回答

13

我建议使用MongoTemplate,并使用Gson/Jackson进行序列化和反序列化。

MongoTemplate拥有CRUD方法,需要传入集合名称和DBObject实体,这与直接使用mongo java驱动程序非常相似。

因此,您将拥有JSON负载,并使用其中一个映射库将其转换为Map

类似于:

反序列化

ObjectMapper mapper = new ObjectMapper(); 
TypeReference<HashMap<String,Object>> typeRef 
        = new TypeReference<HashMap<String,Object>>() {};
HashMap<String,Object> map = mapper.readValue(jsonpayload, typeRef); 
DBObject
DBObject dbObject = new BasicDBObject(map);

MongoTemplate

mongoTemplate.save(dbObject, "collectionname");

你可以对所有其他CRUD操作执行类似的操作。


3
请在此处找到所需代码。
@lombok.Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class Bounty {

  String type;
  Map<String, Object> items;
  Map<String, Object> properties;
  List<Object> required;
}

这是我的代码仓库类

public interface BountyRepository extends MongoRepository<Bounty, String> {
}

下面是一个控制器片段,您可以使用它来尝试:

@GetMapping("/insert/{number}")
    public void insert(@PathVariable int number){
        bountyRepository.save(getBounty(number));
    }


    public Bounty getBounty(int number){
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString1 = "{\n" +
            "    \"type\": \"object\",\n" +
            "    \"properties\": {\n" +
            "        \"name\": {\n" +
            "            \"type\": \"string\",\n" +
            "            \"minLength\": 10\n" +
            "        },\n" +
            "        \"age\": {\n" +
            "            \"type\": \"integer\"\n" +
            "        }\n" +
            "    },\n" +
            "    \"required\": [\n" +
            "        \"name\",\n" +
            "        \"age\"\n" +
            "    ]\n" +
            "}";


        String jsonString2 = "{\n" +
            "    \"type\": \"array\",\n" +
            "    \"items\": {\n" +
            "        \"type\": \"object\",\n" +
            "        \"properties\": {\n" +
            "            \"abc\": {\n" +
            "                \"type\": \"boolean\"\n" +
            "            },\n" +
            "            \"xyz\": {\n" +
            "                \"$ref\": \"#/definitions/\"\n" +
            "            },\n" +
            "            \"asd\": {\n" +
            "                \"type\": \"null\"\n" +
            "            }\n" +
            "        },\n" +
            "        \"required\": [\n" +
            "            \"abc\",\n" +
            "            \"xyz\"\n" +
            "        ]\n" +
            "    }\n" +
            "}";

        try {
            Bounty bounty1 = objectMapper.readValue(jsonString1, Bounty.class);
            Bounty bounty2 = objectMapper.readValue(jsonString2, Bounty.class);


            if (number == 1) return bounty1;
            if (number == 2) return bounty2;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

这是保存后在Mongo中的样子。
/* 1 */
{
    "_id" : ObjectId("58da2390fde4f133178499fa"),
    "_class" : "pani.kiran.sumne.model.Bounty",
    "type" : "object",
    "properties" : {
        "name" : {
            "type" : "string",
            "minLength" : 10
        },
        "age" : {
            "type" : "integer"
        }
    },
    "required" : [ 
        "name", 
        "age"
    ]
}

/* 2 */
{
    "_id" : ObjectId("58da23adfde4f133178499fb"),
    "_class" : "pani.kiran.sumne.model.Bounty",
    "type" : "array",
    "items" : {
        "type" : "object",
        "properties" : {
            "abc" : {
                "type" : "boolean"
            },
            "xyz" : {
                "$ref" : "#/definitions/"
            },
            "asd" : {
                "type" : "null"
            }
        },
        "required" : [ 
            "abc", 
            "xyz"
        ]
    }
}

1
在我的项目中,我的模型具有非常动态的结构,并且我使用了一个java.util.Map对象进行映射。
这是我的Mondo文档模型的实现方式:
@Document(collection = "e_form_data")
public class FormDataModel extends AbstractModel
{
    private static final long serialVersionUID = -1733975205300782871L;
    @Field
    @Indexed(name = "e_form_id_idx")
    private String eFormId;
    @Field
    private Map<String, Object> eFormData;

    public FormDataModel()
    {
        super();
    }

    public FormDataModel(String id, String creatoDa, String modificatoDa, Date dataCreazione, Date dataModifica, String eFormId, Map<String, Object> eFormData)
    {
        super(id, creatoDa, modificatoDa, dataCreazione, dataModifica);
        this.eFormData = eFormData;
        this.eFormId = eFormId;
    }

    public FormDataModel(Map<String, Object> eFormData)
    {
        super();
        this.eFormData = eFormData;
    }

    public Map<String, Object> geteFormData()
    {
        return eFormData;
    }

    public void seteFormData(Map<String, Object> eFormData)
    {
        this.eFormData = eFormData;
    }

    public String geteFormId()
    {
        return eFormId;
    }

    public void seteFormId(String eFormId)
    {
        this.eFormId = eFormId;
    }

    public String getDataInserimento()
    {
        return Utils.formatDateTime(new DateTime(this.dataCreazione.getTime()), "dd/MM/yyyy");
    }

    @Override
    public String toString()
    {
        return "FormDataModel [eFormId=" + eFormId + ", eFormData=" + eFormData + "]";
    }

}

通过使用这个,一切都运行得很好。

谢谢您的回复,但我仍然不确定您如何将JSON结构映射到您建议的Map中? - BiJ

1
您可以使用@DBref映射嵌入式文档。
@Document(collection = "first")
public class First {

    @Id
    private String id;

    @DBRef
    private Properties properties;

    @Field
    private List<String> required;

    // constructor
    // getters and setter    
}

public class Properties {

    @Id
    private String id;

    @DBRef
    private Name name;

    @DBRef
    private Age age;

    // constructor
    // getters and setter   
}

public class Name { ... }
public class Age { ... }

http://www.baeldung.com/cascading-with-dbref-and-lifecycle-events-in-spring-data-mongodb

http://docs.spring.io/spring-data/data-mongo/docs/1.4.2.RELEASE/reference/html/mapping-chapter.html#mapping-usage-references

或者像Angelo Immediata建议的那样

@Document(collection = "first")
public class First {

    @Id
    private String id;

    @Field
    private Map<String, Object> properties;

    @Field
    private List<String> required;

    // constructor
    // getters and setter    
}

您需要一些自定义的读写转换器

http://docs.spring.io/spring-data/data-mongo/docs/1.4.2.RELEASE/reference/html/mapping-chapter.html#mapping-explicit-converters


你提供的例子中,你定义了名为Name、Age等的类。在这里,你假设它们是常量。如果你看一下我的第二个例子,那里的字段是不同的;abc、xyz等。我的问题是如何找到一种通用的方法,适用于这两种情况。 - BiJ
你需要将动态数据放入Java对象、Map、com.mongodb.DBObject或com.mongodb.BasicDBObject com.mongodb.BasicDBList中。请查看此帖子https://dev59.com/GVsV5IYBdhLWcg3wuxCM#35921264。 - Cassian

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接