SharePoint Experts Blog

How to work with dictionaries in SharePoint 2013 and Office 365 workflow

SharePoint 2013 workflows introduced the new type of variable ‘Dictionary’. This type of variable significantly extends functionality of SharePoint workflows. Now you can work with complex objects inside workflows. For example you can query multiple list items and iterate through them using loops. I will describe how to use different types of dictionaries below.

I divided this article to the following sections:

 

Structure of dictionary

Usually we think about a dictionary as a set of key-value pairs. I will use visual notation and JSON notation to represent dictionaries. Classical dictionary as a set of key-value pairs can look like this:

 

JSON view:

{
  "Key1": "Value1",
  "Key2": "Value2",
  "Key3": "Value3",
  "Key4": "Value4"
}

But SharePoint 2013 workflow dictionary is not a classical dictionary. It can also store dictionaries inside other dictionaries. Thus, you can work with quite complex hierarchical objects. It is especially useful if you receive data from external data source, for example web service. It can return complex objects as nested dictionaries. You can see example of a nested dictionary below:

 
 

JSON view:

{
  "Key1": "Value1",
  "Key2": "Value2",
  "Key3": {
    "Key1": "Value1",
    "Key2": "Value2",
    "Key3": "Value3"
  },
  "Key4": "Value4"
}

And now we are coming to the most interesting part. SharePoint 2013 workflow dictionary can store collection of values. It can be collection of plain values like this:

 

JSON view:

[
  "Value1",
  "Value2",
  "Value3",
  "Value4"
]

Or it can be collection of dictionaries or nested dictionaries like this:

 

JSON view:

[
  {
    "Key1": "Value1",
    "Key2": "Value2",
  },
  {
    "Key1": "Value1",    
  },
  {
    "Key1": "Value1",
  }
]

There are no separate types for collection and single dictionary in SharePoint 2013 workflows. A variable with type ‘Dictionary’ can store a collection as well as a single dictionary.

Get values from dictionary

I described types of dictionaries in detail, because you need to know structure of dictionary to process it correctly. Now when we know structure of dictionary we can get values from it using special workflow action ‘Get an Item from a Dictionary’. This workflow action has property ‘Path’. We can use this property to specify path to specific value of dictionary.

Get value from classical key-value pair dictionary

Let as start from simple example.We have a dictionary with classical key-value pair structure:

{
  "Key1": "Value1",
  "Key2": "Value2",
  "Key3": "Value3",
  "Key4": "Value4"
}

We want to get value by key ‘Key2′ from the dictionary. The path will look like this:

Key1

This is an example of configured workflow action:

 

Get value from nested dictionary

Earlier I described that dictionary can contain other dictionaries. Thus, you can store complex objects inside dictionary. Example of nested dictionary:

{
  "Key1": "Value1",
  "Key2": "Value2",
  "Key3": {
    "Key1": "Value1",
    "Key2": "Value2",
    "Key3": "Value3"
  },
  "Key4": "Value4"
}

Let us say we want to get value from nested dictionary stored in the key-value pair with key ‘Key3′ and get value from this dictionary by key ‘Key1′. The path can look like this:

Key3/Key1

This is an example of configured workflow action:

 

 

Get value from item stored in collection

A dictionary can store collections, values or other dictionaries. It is even possible to store collection of nested dictionaries.

Let me show how to get value from collection by index. We will use this approach later to iterate through collection of items. For now I will show hot to get item by specific index. Let us say we have dictionary with collection of plain strings:

[
  "Value1",
  "Value2",
  "Value3",
  "Value4"
]

In this case the path to get the second item by index could look like this:

(1)

Just brackets with index inside. But what if we have collection of nested dictionaries?

[
  {
    "Key1": "Value1",
    "Key2": "Value2"
  },
  {
    "Key1": "Value1",
    "Key2": {
        "Key1": "Value1",
        "Key2": "Value2"
      }
  }  
]

You just need to add path after brackets like this:

(1)/Key2/Key1

This is an example of configured workflow action:

 
 

Build dictionary manually

SharePoint 2013 workflows has out of the box workflow action ‘Build Dictionary’ which allows to create dictionary manually. You can manually specify set of keys and values. The interface of the workflow action looks like this:

This workflow action has significant limitation. It doesn’t allow to use variables inside keys or add keys dynamically. Thus, you can’t create dictionaries dynamically during execution of a workflow. It is possible in Visual Studio workflows only.

Looks like Microsoft developed this workflow action especially for creating parameters for ‘Call HTTP Web Service’ workflow action. This workflow action uses dictionaries to specify parameters and to receive results. You can use this workflow action to call web services, for example SharePoint REST API. This is not always obvious and requires some development experience to understand how to build request to SharePoint REST API or other web service using this workflow action.

Query list items to dictionary by CAML

As I described in previous section you can use ‘Call HTTP Web Service’ workflow action to query SharePoint REST API, but it is not always obvious how to build request. I think SharePoint workflows aim to simplify business processes automation and development process has to be as easy as possible.

I will show how to query list items using CAML conditions and store results to dictionary using custom workflow action Get Items by Query from Workflow Actions Pack. This is much easier than using ‘Call HTTP Web Service’ workflow action.

 Firstly we need to create CAML query. As a proof of concept I want to query all documents with ‘Contract’ string in the name. This is how the CAML query could look:

<View Scope="RecursiveAll">
    <Query>
        <Where>  
            <Contains>
                <FieldRef Name="FileLeafRef" />
                <Value Type="Text">Contract</Value>
            </Contains>          
        </Where>
    </Query>
    <ViewFields>        
        <FieldRef Name="FileRef"/>
        <FieldRef Name="FileLeafRef"/>
    </ViewFields>
</View>

As you see I specified ‘Contains’ condition and ‘ViewFields’. Result dictionary will contain fields specified in the ‘ViewFields’ section.

This is an example of configured workflow actions:

 

I query documents from ‘Documents’ library and store result to dictionary. Then I use the workflow action ‘Get an Item from a Dictionary’ to save ‘FileRef’ field value in the string variable ‘DocumentURL’. To get value from ‘FileRef’ field I use such path:

(0)/FieldValues/FileRef

It means that I return field value from field values of the first returned item only. To get all values I need to iterate through collection of items.

Iterate through items in dictionary

Now when we have dictionary with collection of items I will show how to iterate through them:

 

Firstly I calculate count of items in the dictionary. I use ‘count’ variable to configure loop to iterate ‘count’ times.

Then I initialize index. I use ‘ind’ variable inside path of ‘Get an Item from a Dictionary’ workflow action. The path looks like this:

([%Variable: ind%])/FieldValues/FieldRef

This is a path for my dictionary queried in the previous section of this article. If you have plain collection of string values, the path can look like this:

([%Variable: ind%])

Finally I increment index for the next iteration.

Join values from dictionary to string separated by symbol

Joining values from dictionary can be quite useful. For example if you query multiple list items with email addresses, you can join values from dictionary to single string like this:

email1@domain.com; email2@domain.com;email3@domain;

Unfortunately out of the box workflow actions don’t support such functionality. I will show how to do it using workflow action Join Dictionary Values from Workflow Actions Pack. This workflow action is a part of free subset of string processing workflow actions.

To join values you need to specify separator symbol and pattern for path in the collection like this:

({0})/FieldValues/Email

Thus, all values from path /FieldValues/Email will be joined to single string and separated by specified symbol.

This is an example of configured workflow action:

 

Split string separated by symbol to collection of values

Spiting string to collection can be also useful. For example you may need to split list of email addresses specified by user, iterate through them and send separate message to each of them.

This functionality also is not supported by out of the bow workflow actions. I will show how to use Split String workflow action. This workflow action also is a part of free subset of string processing workflow actions from Workflow Actions Pack.

To split string to collection you need to specify source string and separator. This is an example of configured workflow action:

 

Conclusion

In this article I described how to use dictionaries in SharePoint 2013 and SharePoint Online workflows. You can use them to store classical key-value pairs as well as store nested dictionaries and collections of items. This is especially useful when you query data from external data sources. I hope you will enjoy such a great feature of SharePoint 2013 workflows as dictionaries.

Should you have any questions, feel free to comment.

Posted in: Workflow Actions Pack

  • Paulie M
    Really good article, well done. The Plumsail opens up a lot of functionality which makes things so much easier. I am trialing it at the moment.
  • David Hughes
    Great post, however I’m wondering if you’ve encountered a situation where you cannot reference the dictionary items with an integer value? I’m trying to reference an item by index (since the returned JSON isn’t formatted well) but am getting this error “Details: An unhandled exception occurred during the execution of the workflow instance. Exception details: System.InvalidOperationException: Indexing by an integer value is not supported on an instance of ‘Microsoft.Activities.Dynamic.DynamicJsonObject’.” Any workarounds that you guys know of?