An aggregate root is the domain object used as the entry point to an aggregate. In a taco-ordering application, TacoOrder is the root: a Taco belongs to an order and does not exist outside that order’s context. Ingredient is different. Each Ingredient belongs to its own aggregate, and tacos refer to ingredients through ingredient references. section 3.1.3
That boundary shapes persistence. With JDBC, OrderRepository saves a TacoOrder and the Taco objects that go with it, rather than requiring a separate Taco repository. Saving the order also means inserting its tacos and the Ingredient_Ref rows that connect each taco to its ingredients. The implementation retrieves database-generated IDs so it can make those links. section 3.1.4
package tacos.data;
import java.util.Optional;
import tacos.TacoOrder;
public interface OrderRepository {
TacoOrder save(TacoOrder order);
}
The OrderRepository interface exposes a save operation for TacoOrder, the aggregate root. section 3.1.4
A root-level operation is not automatic in every persistence approach. With the Spring Data R2DBC repositories shown here, tacos must first be saved separately, then the order that references them; reading an order yields taco IDs rather than complete Taco objects. A service in front of both repositories is proposed to provide the desired aggregate-style behavior. section 13.1.3
For MongoDB documents, the boundary appears in the mapping: TacoOrder is annotated with @Document and contains a list of tacos. Taco is saved as part of that order rather than as its own document, while Ingredient is a separate document. section 13.2.1
Listing 13.14 A TacoOrder class annotated for Mongo persistence
package tacos;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
@Data
@Document
public class TacoOrder implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String id;
private Date placedAt = new Date();
private User user;
private String deliveryName;
private String deliveryStreet;
private String deliveryCity;
private String deliveryState;
private String deliveryZip;
private String ccNumber;
private String ccExpiration;
private String ccCVV;
private List<Taco> tacos = new ArrayList<>();
public void addTaco(Taco taco) {
tacos.add(taco);
}
}
The TacoOrder class shows @Document on the root and a list that holds its tacos. section 13.2.1


