I am trying to add a Map field in my oracle nosqltable (in the example given here https://docs.oracle.com/en/database/other-databases/nosql-database/21.1/java-driver-table/accessing-nosql-using-sdf.html) but when saving its not getting saved properly by Spring data.
Customer.java
@NosqlTable(storageGB = 1, writeUnits = 10, readUnits = 10)
public class Customer {
@NosqlId(generated = true)
long customerId;
String firstName;
String lastName;
Map hashMap;
Date createdAt;
@Override
public String toString() {
return "Customer{" +
"customerId=" + customerId +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", createdAt='" + createdAt + '\'' +
", hashMap='" + hashMap + '\'' +
'}';
}
}
CustomerRepostory.java
import com.oracle.nosql.spring.data.repository.NosqlRepository;
public interface CustomerRepository
extends NosqlRepository<Customer, Long>
{
Iterable<Customer> findByLastName(String lastname);
}
When I call the following code to create a customer row :
Customer s1 = new Customer();
s1.firstName = "John";
s1.lastName = "Doe";
HashMap s1Map = new HashMap() ;
s1Map.put("name", "myMap") ;
s1Map.put("use", true);
s1.hashMap = s1Map;
repo.save(s1);
It gets saved as
{
"createdAt": null,
"firstName": "John",
"hashMap": {
"entrySet": null,
"keySet": null,
"loadFactor": 0.75,
"modCount": 2,
"size": 2,
"table": [
null,
null,
null,
null,
null,
null,
{
"hash": 116102,
"key": "use",
"next": null,
"value": true
},
null,
{
"hash": 3373752,
"key": "name",
"next": null,
"value": "myMap"
},
null,
null,
null,
null,
null,
null,
null
],
"threshold": 12,
"values": null
},
"lastName": "Doe"
}
Can someone please help me with correct data type to use for nosql map ?
Map (java.util.Map) is not currently supported, but it is a key roadmap item.
see here https://github.com/oracle/nosql-spring-sdk/issues/18
You can find the current Mapping Between Java and NoSQL JSON Types in the documentation - https://docs.oracle.com/en/database/other-databases/nosql-database/22.2/springsdk/persistence-model.html
In the meantime, it is possible to use the class oracle.nosql.driver.values.MapValue
. Here is an example
import com.oracle.nosql.spring.data.core.mapping.NosqlId;
import oracle.nosql.driver.values.MapValue ;
@NosqlTable(storageGB = 1, writeUnits = 10, readUnits = 10)
public class Customer {
@NosqlId(generated = true)
long customerId;
String firstName;
String lastName;
MapValue map;
@Override
public String toString() {
return "Customer{" +
"customerId=" + customerId +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", map='" + map + '\'' +
'}';
}
}
Here is an example of a call to create a customer row - using multiple types, including other nosql Classes oracle.nosql.driver.values.ArrayValue
. As you can see the syntax is very similar to java.util.Map
. When java.util.Map
will be supported you can migrate easily
Customer c2 = new Customer();
c2.firstName = "John";
c2.lastName = "Josh";
c2.map = new MapValue();
c2.map.put("number field", 1);
c2.map.put("string_field", "string value");
c2.map.put("boolean_field", true);
ArrayValue arrayValue = new ArrayValue();
arrayValue.add(100);
arrayValue.add("102");
arrayValue.add(true);
c2.map.put("json-field", arrayValue);
repo.save(c2);
System.out.println("\nsaved: " + c2);
System.out.println("\nfindAll:");
Iterable<Customer> customers = repo.findAll();
for (Customer s : customers) {
System.out.println(" Customer: " + s);
}
System.out.println("\nfindByLastName: Josh");
customers = repo.findByLastName("Josh");
for (Customer s : customers) {
System.out.println(" Customer: " + s);
}
Here are the outputs - application
saved: Customer{customerId=10, firstName='John', lastName='Doe', map='null'}
saved: Customer{customerId=11, firstName='John', lastName='Smith', map='null'}
saved: Customer{customerId=12, firstName='John', lastName='Josh', map='{"number field":1,"json-field":[100,"102",true],"string_field":"string value"}'}
findAll:
Customer: Customer{customerId=12, firstName='John', lastName='Josh', map='{"json-field":[100,"102",true],"number field":1,"string_field":"string value"}'}
Customer: Customer{customerId=10, firstName='John', lastName='Doe', map='null'}
Customer: Customer{customerId=11, firstName='John', lastName='Smith', map='null'}
findByLastName: Josh
Customer: Customer{customerId=12, firstName='John', lastName='Josh', map='{"json-field":[100,"102",true],"number field":1,"string_field":"string value"}'}
reading using the SQL for Oracle NoSQL Database Shell - if Cloud, you can use the OCI Console
sql-> mode json -pretty
Query output mode is pretty JSON
sql-> select * from customer;
{
"customerId" : 13,
"kv_json_" : {
"firstName" : "John",
"lastName" : "Doe",
"map" : null
}
}
{
"customerId" : 14,
"kv_json_" : {
"firstName" : "John",
"lastName" : "Smith",
"map" : null
}
}
{
"customerId" : 15,
"kv_json_" : {
"firstName" : "John",
"lastName" : "Josh",
"map" : {
"boolean_field" : true,
"json-field" : [100, "102", true],
"number field" : 1,
"string_field" : "string value"
}
}
}
In order to run this example, you need to apply a fix, Otherwise, you will have the following error
Caused by: java.lang.IllegalArgumentException: Entity must not be null!
A fix will be published soon on this GitHub repository https://github.com/oracle/nosql-spring-sdk. Again more information here https://github.com/oracle/nosql-spring-sdk/issues/18
to learn more on MapValue