Someone recently asked me why a one-to-many relationship exists in Contact Builder. And I think that's a very good question (also why there is a many-to-many relationship too). The ability to create these types or relationships has existed since Contact Builder was introduced, over five years ago.

The contact model (in Contact Builder) is pretty much exclusively used by Journey Builder (except for some internal platform purposes, like mapping relationships between the Contact Record to email Subscribers, mobile Contacts, etc).

If I have a one-to-many cardinal relationship to a 'Products' Attribute Set in Data Designer, and there is a single product record for the Contact, and I use that Attribute in a Journey Builder Decision Split Activity, then the Contact is routed through the correct branch:

However, if I update the Product DE (which is the linked Attribute Set in Data Designer) to include the following fields for a given Contact:


Then when I inject the Contact back into the journey multiple times, they are routed through the first branch in the journey each time:

This behavior is understandable, as there is no concept of a one-to-many relationship in Journey Builder Activities.

However, this does beg the question: why can you create one-to-many relationships in the first place? There's no Marketing Cloud application that supports one-to-many (or even many-to-many) contact model relationships that I'm aware of.

Data Designer includes a library of impressive looking Attribute Groups for different use cases, like this one for 'Travel Bookings':

travel bookings attribute group

But I'm can't figure out how anyone is able to actually use this Attribute Group, or any one/many-to-many relationship in the contact model. Can you?


Gortonington suggested in a comment that this might work if there are multiple conditions on a filter criteria. I've tested that, where my Product Attribute Set still contains the three records listed above (see earlier code block).

I created an additional branch in my journey for all products, where the filter criteria is:

Product equals Banana and Product equals Apple and Product equals Carrot

However, the Contact is still routed through the first branch, so that doesn't work.

  • 1
    I wonder if a way to utilize this is to add extra conditions to the split. Have it be (Product = "Apple" AND Product = "Banana"). These would have to be above the individual conditions though as Attribute splits are like CASE SQL statements and once it finds a match (top to bottom) it will exit the conditional, regardless of future matches. I will try to grab some time to test this out and report back. Commented Oct 25, 2018 at 13:18
  • That's a good idea. I've tested this and that doesn't work either. I do have an answer though. I will include the results of this test in my question. Commented Oct 25, 2018 at 20:40
  • I am a bit curious, what was the expectation you had when doing this? That the contact would travel across all branches? To me this is classic IF logic. If first condition is met, do this. Else, try the next one. I use 1:N when I for example look up the status of an order. Commented Dec 13, 2019 at 10:37
  • No, I would not expect that, but I would expect only Attribute Sets with a one-to-one relationship can be selected when configuring Decision Split Activities. Commented Dec 13, 2019 at 10:55
  • Okay, but if you only could select 1:1 relationship you wouldn't be able to do lookup status against orders as I mentioned above. Just trying to wrap my head around why people are saying that there is 1:N in Journey Builder. Commented Dec 16, 2019 at 7:53

4 Answers 4


I've asked around some Salesforce contacts to try and get to the bottom of this. One-to-many relationships from Contact Builder are only applicable in Audience Builder (as Audience Builder uses these relationships).

However you can view this relationship data against the Contact in All Contacts. For example, here is the Attributes page for the Contact in my question:


Here you can see the multiple records related to that Contact in the linked Attribute Set. I can't really see how this would be useful (as you need to open each individual Contact in Contact Builder to see this data) and this data relationship can't be used elsewhere.

I'm concerned that users would make assumptions that these many-type relationships actually serve a purpose in Journey Builder.

  • Thank you for your comment. I wish I'd read this before we'd switched to SFMC specifically for this 1:M functionality, and before I'd spent months trying to jury-rig our implementation into behaving as advertised (at least on the surface). Commented Mar 7, 2019 at 22:14

Have you tried setting this up to run in series, rather than parallel?

As someone mentioned in another answer, Decision Splits act like CASE statements; the first criteria met by the subscriber will be the path they get sent down. You can't send a customer down multiple paths without having them re-enter the journey, and if they keep meeting the criteria they'll keep going down the same path. That's logical.

If your use case is to send a subscriber a comms piece for every one of a given set of Products, then try setting it up as a series of Decision Splits, where a Product entry triggers a comms piece, and people who don't meet the criteria go to a Join that bypasses that comms item and moves on to the next Decision Split.

You can split/nest Product types in some fun ways within Decisions Splits to avoid sending specific combinations, or managing priorities, or whatever else you want to do.

Also, if you want to use a parallel model and don't want people to go down the same path every time, look into using an Update Contact step and a Journey History DE to manage this. It's simple, effective and very extensible, and gives you a useful history record to boot.

We do something similar to what you've outlined, and have not had any problems using a 1:M model to manage a multitude of tasks withing one central Journey.



Old and interesting post.

Isn't that what Attribute to Attribute Comparaisons are made for ?

Depending on how your contacts are injected, you may have to insert an extra condition like journey(fruit_id) = contact(fruit_id) to get the intended split.

Anyway, your post brings to the light how misleading this can be for marketers trying to execute a simple segmentation.


  • 2
    the real answer buried here at the bottom. for anyone following this thread as far as this -yes, this is what 1:N relationships in Contact Builder are useful for even within Journey Builder. say your Customer attend multiple Events (so there's a one to many Customer->Event relationship). And you have a Journey which is fed a Customers Event attendance info via a DE. Then in the Journey Builder you can look up additional Event attributes in Decisions / Waits etc by using journey(event_id) = contact data -> events -> Event Id. In OPs example, you'd need a productId in the entry data
    – Ray
    Commented Aug 23, 2022 at 23:13

A little late to the party, but I agree with Ray.

I have contacts that attend different events and here I see a possible use case for this one-to-many relationship by setting a filter on my entry data extension that chooses only contacts that attended event X.

Doesn't solve the issue from OP with wrong routing in his journey, just offering a use case for one-to-many.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .