Rally - WSAPI: How to GroupBy your WSAPI items
search cancel

Rally - WSAPI: How to GroupBy your WSAPI items

book

Article ID: 131214

calendar_today

Updated On:

Products

Rally On-Premise Rally SaaS

Issue/Introduction

Rally features Kanban Boards and Work Views where query results can be grouped.
Similarly, can we issue WSAPI queries to group our results?

Environment

Release:
Component: ACSAAS

Resolution

This article is an introduction to how to use WSAPI to Group your results. There may be more to this ability beyond what is discussed herein.

WSAPI can be used to group query results of artifacts. Grouping query results can only be done either by a standard (out of box) drop-down field or by 'constrained objects', that is objects that have a one-to-one relationship to your query endpoint/s.

Grouping can not be done by custom fields (even if a simple drop-down), or by objects that have a one-to-many relationship with your query subject.

Let's examine a few examples:
1. Can we group defects by a custom drop-down field?  No. Custom fields can not be used for grouping.

2. Can we group user stories and defects by owner?  Yes. Owner is a standard field that belongs both to defect and hierarchicalrequirement, also it's a 'constrained field' - it has a one-to-one relationship with these artifacts.

3. Can we group a TestCase by its TestCaseResults?  No. A TestCase has a one-to-many relationship to its results. Only 'constrained objects' can be used for grouping.

4. Can we group Artifacts by their Tags?  No. all artifacts have a one-to-many relationship with tags. 


To find out the type of relationship your object/s have you will need to examine the WSAPI endpoint (or endpoints) you query, locate the field you intend to group-by and see if it is either an out-of-box drop-down or a reference to a constrained object that has a one-to-one relationship with your object.  Below we show the above 3rd example: See the 'Results' field of the TestCase endpoint, it tells you a one-to-many relationship. This will be how you find this out:



Now, that we establish what fields can/can't be used for grouping, let's discuss how to construct such a WSAPI query.

Unlike a regular WSAPI query that returns a results page in a flat JSON structure, a group-by query will return a results page in a nested JSON structure. The first JSON layer will include the Groups of your query, where each group may optionally include its Items relevant to your query.

Your query will be in this convention:
https://rally1.rallydev.com/slm/webservice/v2.x/<WSAPI EndPoint>/groupby/<Group-By-Field>?<list-of-arguments>

Some of the available arguments you can use in <list-of-arguments> are:
compact = true/false  - Indicates is to include only the group's references or a more.
start - The starting index of your returned group page.
pagesize - The pagesize for your groups.
includeitems = true/false - Whether or not to include a nested JSON section of the group's items.
itemorder - The sorting of the items inside each group.
itemfetch - List of comma-delimited fields to be returned for the items in each group.
itemquery - (optional) A WSAPI query filter for your groups' items.
itemtypes - A comma-delimited list of WSAPI endpoint types of your group's items.
itemstart - The start index of the internal item page.
itempagesize - The pagesize of items results for each group.
project - A reference to a project for your query.
projectScopeUp - true/false 
projectScopeDown - true/false

There are additional available arguments not discussed here.

Note
- The combination of 'pagesize' and 'itempagesize' can not exceed 500. That is the product of pagesize x itempagesize should be less or equal to 500. 
- itemstart - seems not to function as designed. 

Let's examine two full examples:

Example 1

https://rally1.rallydev.com/slm/webservice/v2.x/artifact/groupby/createdby?start=1&pagesize=15&itempagesize=20&includeitems=true&itemorder=Name ASC&itemfetch=Name,FormattedID&itemquery=(Owner.Name = "<a username>")&itemtypes=Defect,HierarchicalRequirement

This above example targets the Artifact endpoint. It is asking to group results by the 'CreatedBy' field. It is asking to include the items nested within the groups. It queries for items by Owner (see Owner.Name is <a username>) and it's asking to include artifacts of type Defect and HierarchicalRequirement.

Essentially this query will query for defects or user stories that have the owner be the username that's asked for, it will fetch the Name and FormattedID of these objects, then group them by the individuals who created them. 

See below an excerpt of the the returned JSON. Specifically note the nesting of the "Items" structure within the "Group" structure. The initial TotalResultCount points to the total number of groups returned. You can see the first level is of "Group" objects. Inside each Group, you shall see a TotalResultCount of the items within this group followed by a nested "Items" structure:

{
    "GroupedQueryResult": {
        "_rallyAPIMajor": "2",
        "_rallyAPIMinor": "0",
        "Errors": [],
        "Warnings": [],
        "TotalResultCount": 1568,
        "StartIndex": 1,
        "PageSize": 15,
        "Groups": [
            {
                "Group": {
                    "_rallyAPIMajor": "2",
                    "_rallyAPIMinor": "0",
                    "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/user/<USER_OID>",
                    "_refObjectUUID": "<OBJECT_UUID>",
                    "_objectVersion": "1",
                    "_refObjectName": "User 1"
                },
                "TotalResultCount": 2,
                "StartIndex": -1,
                "PageSize": 20,
                "Items": [
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "4",
                        "_refObjectName": "firstUserStory1",
                        "FormattedID": "US6",
                        "DirectChildrenCount": 0,
                        "Name": "firstUserStory1",
                        "_type": "HierarchicalRequirement"
                    },
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "3",
                        "_refObjectName": "TestUserStory4",
                        "FormattedID": "US10",
                        "DirectChildrenCount": 0,
                        "Name": "TestUserStory4",
                        "_type": "HierarchicalRequirement"
                    }
                ]
            },
            {
                "Group": {
                    "_rallyAPIMajor": "2",
                    "_rallyAPIMinor": "0",
                    "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/user/<USER_OID>",
                    "_refObjectUUID": "<OBJECT_UUID>",
                    "_objectVersion": "6",
                    "_refObjectName": "User 2"
                },
                "TotalResultCount": 1,
                "StartIndex": -1,
                "PageSize": 20,
                "Items": [
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "4",
                        "_refObjectName": "firstUserStory1",
                        "FormattedID": "US6",
                        "DirectChildrenCount": 0,
                        "Name": "firstUserStory1",
                        "_type": "HierarchicalRequirement"
                    }
                ]
            }
}

Example 2

https://rally1.rallydev.com/slm/webservice/v2.x/artifact/groupby/project?start=1&pagesize=15&itempagesize=20&includeitems=true&itemorder=Name ASC&itemfetch=Name,FormattedID&itemquery=(Tags.Name contains "MyTag")&itemtypes=Defect,HierarchicalRequirement,Task,TestCase,PortfolioItem/Feature

This example also targets the Artifact endpoint. It will group results by Project. It posts a query for artifacts that have Tags which contain "MyTag", it's asking only for artifact types Defect,HierarchicalRequirement,Task,TestCase and PortoflioItem/Feature to be returned and it is asking to group the results by Project.

Below is an excerpt of the results. Again, you shall examine the first TotalResultCount of 18, which means 18 groups returned - 18 project. The first group is a project named: "Sample Project", it has a nested Items structure that has 1 result which is a User Story (hierarchicalrequirement). The second group is a project named: "Sample Team 2_1", it has 2 items of a task and a feature:

{
    "GroupedQueryResult": {
        "_rallyAPIMajor": "2",
        "_rallyAPIMinor": "0",
        "Errors": [],
        "Warnings": [],
        "TotalResultCount": 18,
        "StartIndex": 0,
        "PageSize": 15,
        "Groups": [
            {
                "Group": {
                    "_rallyAPIMajor": "2",
                    "_rallyAPIMinor": "0",
                    "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/project/<PROJECT_OID>",
                    "_refObjectUUID": "<OBJECT_UUID>",
                    "_objectVersion": "10",
                    "_refObjectName": "Sample Project"
                },
                "TotalResultCount": 1,
                "StartIndex": 0,
                "PageSize": 20,
                "Items": [
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "10",
                        "_refObjectName": "MyTest11",
                        "FormattedID": "US252",
                        "DirectChildrenCount": 0,
                        "Name": "MyTest11",
                        "_type": "HierarchicalRequirement"
                    }
                ]
            },
            {
                "Group": {
                    "_rallyAPIMajor": "2",
                    "_rallyAPIMinor": "0",
                    "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/project/<PROJECT_OID>",
                    "_refObjectUUID": "<OBJECT_UUID>",
                    "_objectVersion": "4",
                    "_refObjectName": "Sample Team 2_1"
                },
                "TotalResultCount": 2,
                "StartIndex": 0,
                "PageSize": 20,
                "Items": [
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "2",
                        "_refObjectName": "TaskNumber28",
                        "FormattedID": "TA28",
                        "DirectChildrenCount": 0,
                        "Name": "TaskNumber28",
                        "_type": "Task"
                    },
                    {
                        "_rallyAPIMajor": "2",
                        "_rallyAPIMinor": "0",
                        "_ref": "https://rally1.rallydev.com/slm/webservice/v2.x/hierarchicalrequirement/<STORY_OID>",
                        "_refObjectUUID": "<OBJECT_UUID>",
                        "_objectVersion": "2",
                        "_refObjectName": "MyFirstFeature",
                        "FormattedID": "F1",
                        "DirectChildrenCount": 0,
                        "Name": "MyFirstFeature",
                        "_type": "PortfolioItem/Feature"
                    }
                ]
            }
}