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@Documentpublic 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@Documentpublic 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.