TL;DR
- AEP B2C doesn't support 1:M or M:N relationships via UI or API — only 1:1 relationship descriptors
- String arrays as foreign keys can enable 1:M-style traversal in segmentation
- ExperienceEvents work for time-series data but have consent policy limitations in AJO
- Lookup datasets don't support real-time audiences or consent policies
- Denormalization into profile arrays is best for small, bounded collections
The Problem: AEP's Relationship Limitations
According to Adobe's official documentation, for B2C implementations, the Schema Editor UI only allows configuring one-to-one relationships between schemas. This is a significant constraint when dealing with real-world data models.
Common scenarios that require 1:M or M:N relationships:
- A customer with multiple loyalty program memberships
- A user associated with multiple brands or product lines
- A profile with multiple consent records per channel/brand
- A customer with multiple addresses or payment methods
- Users belonging to multiple households or accounts
Important Clarification
The UI/API only lets you define a one-to-one relationship descriptor between schemas. However, the source relationship field can be a string array, meaning a single profile/event record can reference multiple destination entities — which effectively enables one-to-many style traversal in multi-entity segmentation.
The Working "1:M-Style Traversal" Pattern
Here's the pattern that actually works for achieving one-to-many behavior in AEP:
CustomerProfile {
customerId = primary identity (person)
productSkuIds = string[] // Array of foreign keys
}
// Destination Schema (Lookup/Dimension entity)
ProductCatalog {
productSkuId = string primary identity // Non-person namespace
brand = string
categoryId = string
price = number
}
// Relationship:
CustomerProfile.productSkuIds[] → ProductCatalog.productSkuId
The key insight: while the relationship descriptor is technically 1:1, using a string array as your foreign key field allows a single profile to reference multiple destination entities.
Approach 1: ExperienceEvent Schema
In projects where we had a one-to-many relationship — such as a single user associated with multiple programs or brands — we modeled program/brand level attributes within an ExperienceEvent schema.
When to Use ExperienceEvents
- High-volume, time-series data (purchases, page views, interactions)
- When you need historical context for each relationship
- Data that changes frequently over time
ExperienceEvent Challenges
Challenge 1: Consent Policies in AJO
Because consent information stored at the ExperienceEvent level cannot be directly evaluated in consent policies in Adobe Journey Optimizer. AJO consent policies only evaluate profile-level attributes.
Challenge 2: Audience Segmentation Issues
When multiple consent events exist for a single profile, audience segmentation cannot reliably return the most recent consent value. There are workarounds using derived attributes to store important fields at the profile level, but this adds complexity.
ExperienceEvent Schema Example
{
"type": "object",
"title": "Brand Consent Event",
"properties": {
"brandId": {
"type": "string",
"title": "Brand Identifier"
},
"emailConsent": {
"type": "string",
"enum": ["opted_in", "opted_out", "pending"]
},
"smsConsent": {
"type": "string",
"enum": ["opted_in", "opted_out", "pending"]
},
"consentTimestamp": {
"type": "string",
"format": "date-time"
}
}
}
Approach 2: Lookup Datasets
Lookup (dimension) datasets allow you to enrich profile data with reference data. However, they come with significant limitations.
Lookup Dataset Limitations
| Limitation | Impact |
|---|---|
| No Consent Policy Support | Lookup attributes cannot be referenced or evaluated in consent policies |
| No Real-Time Support | Lookup fields cannot be used to build real-time audiences |
| Performance Constraints | Dimension datasets must remain small for segmentation engine to load into memory |
| No Immediate Qualification | Unsuitable for scenarios requiring immediate audience qualification |
Real-Time Limitation is Critical
If your use case requires real-time personalization or immediate audience qualification, lookup schemas are not the right choice. This makes them unsuitable for many CDP activation scenarios.
Approach 3: Denormalization with Profile Arrays
For small, bounded collections, denormalizing data directly into profile arrays is often the cleanest solution.
When to Use Profile Arrays
- Small, bounded collections (e.g., max 5-10 items)
- Data that doesn't change frequently
- When you need real-time segmentation on the relationship data
- When consent policies need to reference the data
Profile Array Example
{
"type": "object",
"title": "Customer Loyalty Programs",
"properties": {
"loyaltyPrograms": {
"type": "array",
"items": {
"type": "object",
"properties": {
"programId": { "type": "string" },
"programName": { "type": "string" },
"tier": { "type": "string" },
"pointsBalance": { "type": "integer" },
"enrollmentDate": { "type": "string", "format": "date" },
"emailConsent": { "type": "boolean" }
}
}
}
}
}
Pro Tip: Array Size Matters
Large arrays can negatively impact profile and segmentation performance. Adobe recommends keeping arrays bounded and small. If you expect unbounded growth, consider ExperienceEvents instead.
Approach 4: Bridge/Association Datasets for M:N
For true many-to-many relationships, model using an association/bridge dataset that connects entities.
Person { personId (primary identity) }
// Association Dataset (Bridge)
PersonProductAssociation {
personId = string
productId = string
relationshipType = string // "purchased", "wishlisted", etc.
timestamp = datetime
}
// Product Catalog (Lookup)
Product { productId (primary identity), name, category, ... }
Comparison: Which Approach to Use?
| Approach | Real-Time | Consent Policies | Best For |
|---|---|---|---|
| Profile Arrays | Yes | Yes | Small, bounded 1:M relationships |
| ExperienceEvents | Yes | No (AJO limitation) | Time-series, high-volume data |
| Lookup Datasets | No | No | Reference data enrichment, batch |
| Bridge Datasets | Partial | No | True M:N with history |
Real-World Recommendations
For 1:M Relationships
- Denormalize into profile arrays for small, bounded collections
- Use ExperienceEvents for time-series/high-volume data
- Use dimension/lookup entities + many-to-one relationships where appropriate (keeping dimension datasets small)
For M:N Relationships
- Model using an association/bridge dataset (personId + entityId)
- Use ExperienceEvents that naturally connect the entities
- Optionally enrich the entity side via lookup/dimension datasets
Performance Considerations
Key Performance Implications
- Large arrays can negatively impact profile/segmentation performance
- Dimension entities must remain small enough for the segmentation engine to load into memory
- Oversized dimension datasets will cause performance degradation
- Monitor your array sizes and dimension dataset sizes regularly
Workaround for Consent with ExperienceEvents
If you must store consent at the event level but need it for AJO policies, use Derived Attributes to sync critical fields to the profile level:
// Derived Attribute Definition (Conceptual)
// Copies latest consent value from events to profile
SELECT
personId,
LAST_VALUE(emailConsent) OVER (
PARTITION BY personId
ORDER BY consentTimestamp
) as currentEmailConsent
FROM brand_consent_events
This approach adds complexity but bridges the gap between event-level storage and profile-level policy requirements.
Conclusion
AEP's relationship model has real constraints, but understanding them helps you design schemas that actually work. The key takeaways:
- There's no magic bullet — each approach has trade-offs
- Profile arrays are best for small, bounded 1:M with real-time needs
- ExperienceEvents work for high-volume data but have AJO consent limitations
- Lookups are useful but not for real-time or consent policies
- Plan for scale — performance degrades with oversized arrays and dimensions
The best approach depends on your specific use case, data volumes, and whether you need real-time activation or consent policy evaluation.