To me, useOneAsMany is to BTP Mappings what offside is in soccer: incredibly difficult to understand or explain to a newcomer.
I don't need to use it everyday, so I keep forgetting how it works myself - at the same time, I find the various explanations out there very complicated and hard to follow. So I'll give it a try myself, hoping it will at least help me remember next time I need to use it:
In short: useOneAsMany allows you to reuse a field that occurs only once in a context that occurs multiple times. Think header field on item level.
The confusing part, to me, are the three input variables. Two would make total sense: One that holds the field you want to repeat and one that details how often to repeat. But it has three, and that one tells the system when to inject a context change.
Let's take our example ("use header field on item level") as an example to summarise the parameters:
- Parameter 1 holds the value you want to multiply (i.e. the header field)
- Parameter 2 indicates when the context change occurs (this would be your item node - don't use a field from the item node, use the item node itself!)
- Parameter 3 holds the how often you want to multiply (i.e. an item field that occurs as often as you want your target field to occur, e.g. item number)
If you were just after the How-To, you can stop reading. If you're interested in the background, read on:
BTP builds the target XML in queues. It always goes by the target side, from the top level to the bottom level. Each target field gets its own queue. Say you have a field "item category" and you want to determine it based on a fixed header field "Order Reason". If you simply map them directly (without useOneAsMany), the following happens when BTP tries to build a target queue for item category:
- BTP looks at the source field
- It finds Order Reason
- It sees that Order Reason occurs once in the source
- It maps it for the first item
- No other items get an item category
As the queues are separate, BTP doesn't care how often the fields left and right of "item category" occur. It looks at each field in isolation.
UseOneAsMany multiplies those fields: It pretends that "item category" (parameter 1) occurs as many times as the reference field (i.e. item number) you used. So if you have 10 item IDs, order reason will be mapped 10 times to item category.
And what is the purpose of the second parameter? It tells BTP when to use the next order's header value (context change). Imagine you have 2 orders in your payload. Order 1 has 5 items and order reason A, order 2 has 10 items and order reason B. If parameter 2 didn't exist, we would have halfway solved our problem but introduced a bigger one:
- BTP looks at the source field
- It takes the first Order Reason it finds in the current context (order A)
- It looks at the item ID (the multiplier) and sees that there are 15 items
- It blindly maps order reason 15 times to item category - 5 go to order A, 10 go to order B
- Order 2 receives the item categories of order 1
So the second parameter tells BTP: When you reach the fifth item, start a new queue for field item category for order 2, load the first value for parameter 1 from the current context (order 2), then continue mapping.
Quirks
Update 2026-07-14:
I recently had a special case. The source structure had items and each item had 0:n partners. The target structure, however, had the partners directly under the root, so there was no convenient item nesting - instead, the item number had to be mapped into the target partner structure. This is where useOneAsMany came in.
Had I not used useOneAsMany, only the first partner would have received an item number (as each item only has one number but several partners). So I mapped:
- the ItemID as the first parameter of useOneAsMany (the field I wanted to repeat)
- the Party node as the second parameter of useOneAsMany (indicates the context changes)
- and Party->PartyID as the third parameter of useOneAsMany (indicating how often I to repeat the ItemID, once for each partner)
However, this dumped in BTP with the error "Too many values in first queue in function useOneAsMany. It must have the same number of contexts as second queue".
Why did it dump for the useOneAsMany? I'm still not entirely sure how this works internally, but it's a combination of the number of target items the mapping engine expects and the context of the useOneAsMany. Because, I didn't actually have to change the mapping or context of ItemID and Party (first and second parameter).
All I had to do was change the context of the third parameter (PartyID) from Party to Item - I ended up simply mapping Party to both parameter 2 and 3.
Why? I'm not sure. For background:
- the engine expects parameters 1 and 2 to have the same number of contexts - this was clearly the case. Both Party and ItemID sit underneath Item and have the same contexts. Even if no Party exists for an item, it still has an (empty) context, so this error should not occur.
- for parameters 2 and 3, the mapper expects the same number of values (irrespective of contexts). Because PartyID has a 1:1 relationship to Party, this also was absolutely the case. In the BTP queue display, I see 9 (empty) values for Party and 9 (actual) values for PartyID.
Assume that items 1 and 3 have parties, item 2 does not. With the context of PartyID at Party, nothing is present in parameter 3 for item 2. With the context of of PartyID at Item, at least a context change is present in parameter 3 for item 2. So the only explanation I have for an error in this scenario is that the empty context (the item without partner) trips the mapper up. Something like: "I just did a context change from item 1 to item 2 (parameter 2), I have an item ID for item 2 (parameter 1 ) but I don't have any template (= parameter 3), not even an empty context, for how often to repeat item ID for item 2. Panic!"
Aside from the error, what's the impact of that context change on the behaviour of useOneAsMany? It tells useOneAsMany how often to repeat parameter 1 in this context (i.e. for this item). Say our item has 4 partners. In this case, setting the context of PartyID to Party repeats the ItemID 4 times. But since PartyID has a 1:1 relationship to Party, we can just as well set it to Item, because both Party and PartyID occur exactly 4 times for the item. The only time you have to be careful is if your iterator (PartyID in this case) occurs more often than your parameter 2 (which signals the context changes).
TL;DR: Sometimes you have to change the context of the third parameter if the mapper complains about an alignment issue between useOneAsMany parameters one and two.