Home Services Blog About Contact

One-to-Many and Many-to-Many Schema Relationships in AEP CDP

If you've ever tried to model complex data relationships in Adobe Experience Platform for B2C implementations, you've probably hit a wall. The Schema Editor only supports one-to-one relationships. So what do you do when your business requires one-to-many or many-to-many relationships? Let's break it down.

AEP Schema Relationships Diagram

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:

// Source Schema (Profile or Event)

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 Profile
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

  1. Denormalize into profile arrays for small, bounded collections
  2. Use ExperienceEvents for time-series/high-volume data
  3. Use dimension/lookup entities + many-to-one relationships where appropriate (keeping dimension datasets small)

For M:N Relationships

  1. Model using an association/bridge dataset (personId + entityId)
  2. Use ExperienceEvents that naturally connect the entities
  3. 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.

AEP Schema Design Real-Time CDP XDM Data Modeling Lookup Datasets ExperienceEvents

Need Help with AEP Schema Design?

Our team has deep experience modeling complex data relationships in Adobe Experience Platform. Let's design a schema architecture that scales.

Get Expert Help →