Progress will discontinue Telerik Platform on May 10th, 2018. Learn more

Expand Expression Examples

In this article you will find examples for expand expressions that cover the full gamut of expanding options. All examples are based on the Friends sample app data structure.

The content in this article is organized as follows:

Basic Relation Expansion

The most simple expand expression only specifies an expand field. As explained in Expand Expression Format, the expand expression format depends on where the relation is held:

The examples in this article use the data.expand() approach, which is one of two available options. The alternative Everlive.Query() approach is required in some situations such as when sorting or paging data before expanding it. See Defining a Relation Expanding Expression for more information.

The Queried Content Type Holds the Relation

When you are querying the content type that holds the relation field you need to specify that field in your expand expression and to include the related content type name using TargetTypeName.

The following example returns all Activities but replaces the Likes field that normally stores User IDs with the respective user object(s) from the related Users content type.

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities
Headers:
    X-Everlive-Expand: {
        "Likes": {
            "TargetTypeName" : "Users"
            }
    }

The request returns this result (using the Telerik Platform Friends social sample app). Some lines are skipped for brevity:

{
    "Count": 2,
    "Result": [{
        "Likes": [{
            "Username": "seth",
            "DisplayName": "Seth Peterson",
            ....
        }],
        "Text": "It is finally time for graduation! Good job everyone, we made it."
            ....
    }, {
        "Likes": [],
        "Text": "The most amazing sunset I have ever seen at Phuket, Thailand",
        ...
    }]
}

The Queried Content Type Does Not Hold the Relation

When the relation field is held in the related content type, you need to use a different expand expression format that specifies them.

For example, if you want to retrieve the Activities that have been liked by a given user, you can make a request to the Users content type, specifying that the Activities' Likes field relates the two content types:

Request:
    GET https://api.everlive.com/v1/your-app-id/Users/item-id
Headers:
    X-Everlive-Expand: {
        "Activities.Likes": true
        }

The result is a single User object with a property Activities.Likes that contains an array of all Activities that have the user's ID in their Likes fields:

{
    "Result": {
        "Username": "seth",
        ...
        "Activities.Likes": [{
            "Text": "It is finally time for graduation! Good job everyone, we made it.",
            ...
        }]
    }
}

Renaming the Expanded Field

When expanding fields, the default behavior is to use the content type field name for the expanded field in the result. To rename the return field, pass the ReturnAs expand expression option. You can use it regardless of what side of the relation you are querying.

To preserve the integrity of your data, avoid returning a renamed field to the server, because this will add the new field to the database with the nested object inside.

The following example renames the return field from "Likes" to "UsersWhoLikeThisActivity":

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities
Headers:
    X-Everlive-Expand: {
        "Likes": {
            "TargetTypeName" : "Users",
            "ReturnAs" : "UsersWhoLikeThisActivity"
        }
    }

The result will look like this:

{
    "Result": [{
      "UsersWhoLikeThisActivity": [{
          "Username": "seth",
          "DisplayName": "Seth Peterson",
          ....
      }],
      "Text": "It is finally time for graduation! Good job everyone, we made it."
          ....
    }, {
      "UsersWhoLikeThisActivity": [],
      "Text": "The most amazing sunset I have ever seen at Phuket, Thailand",
      ...
    }],
    "Count": 2
}

The ReturnAs option is very important when working with the Backend Services RESTful API in strongly typed languages such as C# and Java. In them, changing the return field type from GUID or UUID to an object breaks the deserialization from JSON to an object. Because this is exactly what the expand feature does, you need to use ReturnAs to rename the return property for better mapping to classes.

Let's take a standard activity from the Telerik Platform sample social app:

{
    "Activity": {
        "Id": "activityId",
        "Likes": [
            "user1Id",
            "user2Id"
        ]
    }
}

where Likes is a relation field. In a strongly typed language such as C# or Java this field will be deserialized to IEnumerable<Guid> or ArrayList<UUID> respectively. Adding a simple expand expression like this:

X-Everlive-Expand: {
    "Likes" : {
        "TargetTypeName" : "Users",
        "ReturnAs": "Likes"
    }
}

will break any existing application, because Telerik Platform will return something like:

{
    "Activity": {
        "Id": "activityId",
        "Likes": [{
            User1Object...
        }, {
            User2Object...
        }]
    }
}

where Likes cannot be deserialized to a collection of GUID or UUID.

The ReturnAs configuration option can be used to return the result as UsersWhoLikeThisActivity along with a new property of type IEnumerable<User> or ArrayList<User> on the client side.

Filtering

When expanding one-to-many relations, you can include an optional filtering expression to narrow down on the expanded data.

Filtering the result of the expand expression is possible only when reading by ID in the base query.

Filtering can be used regardless of whether you are querying the content type that holds the relation or not.

For example, the following expand expression filters the expanded data by the Email field.

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities/activityId
Headers:
    X-Everlive-Expand: {
        "Likes": {
            "TargetTypeName" : "Users",
            "ReturnAs": "UsersWhoLikeThisActivity",
            "Filter": { "Email": { "$regex": "@telerik.com$" } }
        }
    }

Telerik Platform executes the following request (in a addition to the "by ID" request) behind the scenes, which returns all users with an email in the "telerik.com" domain who liked our activity.

Request:
    GET https://api.everlive.com/v1/your-app-id/Users
Headers:
    X-Everlive-Filter: { "$and": [
        {"Email": { "$regex": "@telerik.com$"} },
        { "Id": { "$in" : [ "user1Id", "user2Id" ] } }
    ]}

Sorting

Similar to filtering, a standard Telerik Platform sorting expression can be added to the expand expression. It sorts the array of expanded data in case of one-to-many relations. In case of one-to-one relations, the sorting expression is ignored.

Sorting is applied only for "by ID" requests. "By filter" request that return a single item are not considered a "by ID" case.

Sorting can be used regardless of whether you are querying the content type that holds the relation or not.

The following example request returns the activity with the specified ID together with all users who liked it sorted by their Email field in ascending order.

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities/activityId
Headers:
    X-Everlive-Expand {
        "Likes": {
            "TargetTypeName" : "Users",
            "ReturnAs": "UsersWhoLikeThisActivity",
            "Sort": { "Email" : 1 }
        }
    }

Paging

When you are dealing with a great amount of result data you can use paging to ensure that the service returns the requested items in a timely fashion and that the response will not consume an excessive amount of bandwidth. Paging is implemented using the Skip and Take options.

Because the result order could be different on each request, it is strongly recommended to use sorting along with paging.

The following example request returns only items 11 through 20.

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities/activityId
Headers:
    X-Everlive-Expand {
        "Likes": {
            "TargetTypeName" : "Users",
            "ReturnAs": "UsersWhoLikeThisActivity",
            "Skip": 10,
            "Take": 10
        }
    }

Selecting Return Fields

A fields expression is used to project the result (take only a subset of fields). It must be a valid Telerik Platform fields expression.

Fields selection can be used regardless of whether you are querying the content type that holds the relation or not.

Fields and SingleField cannot be used simultaneously.

The following example selects DisplayName and Email for returning and explicitly excludes Id which is otherwise always returned.

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities/activityId
Headers:
    X-Everlive-Expand {
        "Likes": {
            "TargetTypeName" : "Users",
            "ReturnAs": "UsersWhoLikeThisActivity",
            "Fields": {
                "DisplayName": 1, "Email": 1, "Id": 0
            }
        }
    }

And the result:

{
    "Id": "activityId",
    "UsersWhoLikeThisActivity": [{
        "DisplayName": "Andy Gerald",
        "Email": "andy.gerald@telerik.com"
    }, {
        "DisplayName": "Michael Taylor",
        "Email": "michael.taylor@telerik.com"
    }]
}

Returning a Single Field

There are cases where you are interested in just a single field of an expanded object such as the DisplayName field of a user object. The SingleField expand expression option allows you to completely replace the expanded object with that field's value.

Fields and SingleField cannot be used simultaneously.

The following example reads an activity by ID and adds all users who liked the activity, but instead of returning the entire user object, it replaces it with the value of the DisplayName field:

Request:
    GET https://api.everlive.com/v1/your-app-id/Activities/activityId-here
Headers:
    X-Everlive-Expand {
        "Likes": {
            "TargetTypeName": "Users",
            "ReturnAs": "UsersWhoLikeThisActivity",
            "SingleField": "DisplayName"
        }
    }

And the result:

{
    "Id": "activityId-here",
    "Text": "It is finally time for graduation! Good job everyone, we made it.",
    "UsersWhoLikeThisActivity": [
        "Andy Gerald",
        "Michael Taylor"
    ]
}

Expanding File Metadata

Another example is expanding file metadata. Assume that you have a Books content type that stores a book collection. Each book has a field Cover of type File defined in the content type's structure that stores the Id of the book's cover image. If you want to retrieve the Uri where the image file is stored instead of retrieving its full metadata, you can do so by using SingleField like this:

Request:
    GET https://api.everlive.com/v1/your-app-id/Books/item-id
Headers:
    X-Everlive-Expand: {
        "Cover":{
            "TargetTypeName" : "System.Files",
            "ReturnAs":"CoverURL",
            "SingleField":"Uri"
        }
    }

This request results in:

{
    "CoverURL": "https://bs1.cdn.telerik.com/v1/SLTCCCkPnud4GC29/0000bte0-c286-12e4-b57c-2939r6e80316",
    "CreatedAt": "2015-03-04T15:50:13.346Z",
    "ModifiedAt": "2015-03-04T15:50:13.346Z",
    "CreatedBy": "00000000-0000-0000-0000-000000000000",
    "ModifiedBy": "00000000-0000-0000-0000-000000000000",
    "Owner": "00000000-0000-0000-0000-000000000000",
    "Id": "0000f420-f286-11e4-9c5d-c5653ab2b427",
    "Meta": {
        "Permissions": {
        "CanRead": true,
        "CanUpdate": true,
        "CanDelete": true
        }
    }
}

See Also

To learn how to define an expand expressions, see Defining an Expand Expression.

Contact us: +1-888-365-2779
sales@telerik.com
Copyright © 2016-2017, Progress Software Corporation and/or its subsidiaries or affiliates. All rights reserved.