Skip to main content

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.