Saving JSON schema in mongodb using spring
I am new to Spring data and mongodb. I have a JSON object that is a JSON schema and I need to store this in mongodb using Spring data. But the problem with JSON schema is the JSON Schema structure - dynamic; for example below, two valid JSON schemas with a completely different structure.
{
"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"
]
}
}
How can I define the JAVA POJO class so that I can map the above JSON to a specific class and store it in mongodb. Or is it possible to perform a CURD operation in Spring without mapping it to a POJO class?
source to share
I would recommend using MongoTemplate and serialize and deserailize with Gson / Jackson .
The Mongo template has CRUD methods that take a collection name and a DBObject, which is very similar to what you have to use the mongo java driver directly.
So, you will have a json payload and use one of the maps library to convert them to Map
.
Something like
Deserialise
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");
You can do something similar for all other CRUD operations.
source to share
Please find the required code here.
@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;
}
Here is my repository class
public interface BountyRepository extends MongoRepository<Bounty, String> {
}
And here is a snippet of the controller you can use to try it out
@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;
}
This is what it looks like in Mongo after saving.
/* 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"
]
}
}
source to share
In my project I had a very dynamic structure of my models and I mapped them using an object java.util.Map
this is how my mondo document model is implemented:
@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 + "]";
}
}
When using this, everything works pretty well
source to share
You can match subdocuments with @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
Or, as Angelo Immediata suggested
@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
}
And you will need some custom read / write converters
source to share
FWIW, MongoDB 3.6 introduced JSON Schema validation support at the database level. You can read more on the MongoDB blog . Hope it helps!
source to share