Spring Data Hierachy Mapping
Java POJOs rarely exist in isolation. Quite often there are dependent objects associated with the main object. A Person
may have an Address
, an Account
might have a CreditCard
and so on. Spring Data Aerospike's implementation supports aggregating these object hierarchies into a single Aerospike record. Children objects will be stored in maps inside the record and may be used as part of the filter criteria for loading records.
A simple example of this is a Person
with two Address
fields - one for their home and one for their work. The Person
object might look like:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Document
public class Person {
@Id
private long id;
private String firstName;
@Indexed(name = "lastName_idx", type = IndexType.STRING)
private String lastName;
@Field("dob")
private Date dateOfBirth;
private Address homeAddress;
private Address workAddress;
}
The Address
class can be simple too:
@AllArgsConstructor
@NoArgsConstructor
@Data
@Document
public class Address {
private String line1;
private String suburb;
private String state;
private String zipCode;
}
Note that as the Address
objects are not stored in the database in their own right but rather as children of the Person
object there is no need for an @Id
field nor for an AddressRepository
interface.
Saving a Person
and associated Address
fields to Aerospike is simple:
Address homeAddress = new Address("123 Main St", "Como", "CO", "81111");
Address workAddress = new Address("222 Smith St", "New York", "NY", "10003");
Person person = new Person(10001, "Bob", "Jones", new Date(), homeAddress, workAddress);
personRepsitory.save(person);
This produces:
aql> select * from test.Person where pk = "10001"
[
[
{
"PK": "10001",
"firstName": "Bob",
"lastName": "Jones",
"dob": 1679010467849,
"@_class": "com.aerospike.sample.model.Person",
"workAddress": {
"@_class": "com.aerospike.sample.model.Address",
"line1": "222 Smith St",
"state": "NY",
"suburb": "New York",
"zipCode": "10003"
},
"homeAddress": {
"@_class": "com.aerospike.sample.model.Address",
"line1": "123 Main St",
"state": "CO",
"suburb": "Como",
"zipCode": "81111"
}
}
],
[
{
"Status": 0
}
]
]
Query methods can now be added to the PersonRepository
interface to use these sub-objects as criteria:
public interface PersonRepository extends AerospikeRepository<Person, Long> {
public List<Person> findByLastName(String lastName);
public List<Person> findByHomeAddressState(String state);
}
Note that Spring Data Aerospike does have a finite depth of nested hierarchy it can traverse to find records.