How to Group Results in WOQL

Open inAnthropic

What you'll achieve By the end of this guide, you will know how to group and aggregate query results using WOQL.

Prerequisites: TerminusDB running on localhost:6363 with the Star Wars dataset cloned. If you haven't done this yet, follow the Explore a Real Dataset tutorial (Steps 1–2), or run:

curl -u admin:root -X POST http://localhost:6363/api/clone/admin/star-wars \
  -H "Content-Type: application/json" \
  -H "Authorization-Remote: Basic cHVibGljOnB1YmxpYw==" \
  -d '{"remote_url": "https://data.terminusdb.org/public/star-wars", "label": "Star Wars", "comment": "Star Wars dataset"}'

How to use Group By

If we need to group variables according to some criteria, we can create an aggregate of solutions using group_by.

A group by is composed of a focus, a template, and a group together with a query.

Single Variable Template (Flat Array)

When grouping a single variable, the template produces a flat array of values:

Example: JavaScript
let v = Vars("person", "label", "eyes", "group", "member");
limit(1)
.group_by(
  "eyes",
  ["label"],
  v.group,
  and(triple(v.person, "rdf:type", "@schema:People"),
      triple(v.person, "label", v.label),
      triple(v.person, "eye_color", v.eyes)))

The first argument, here "eyes" refers to the eyes variable, and is the variable around which to form the group, the focus.

The second ["label"] is the template, which refers to the variable "label". Since the template contains only one variable, the results will be collected as a flat array.

The third variable v.group, is the group variable, which will include groups of templates for each set of solutions which shares a focus.

This raw query output will be:

Example: JSON
{
    "eyes": {
        "@type": "xsd:string",
        "@value": "black"
    },
    "group": [
        {
            "@type": "xsd:string",
            "@value": "Greedo"
        },
        {
            "@type": "xsd:string",
            "@value": "Nien Nunb"
        },
        {
            "@type": "xsd:string",
            "@value": "Gasgano"
        },
        {
            "@type": "xsd:string",
            "@value": "Kit Fisto"
        },
        {
            "@type": "xsd:string",
            "@value": "Plo Koon"
        },
        {
            "@type": "xsd:string",
            "@value": "Lama Su"
        },
        {
            "@type": "xsd:string",
            "@value": "Taun We"
        },
        {
            "@type": "xsd:string",
            "@value": "Shaak Ti"
        },
        {
            "@type": "xsd:string",
            "@value": "Tion Medon"
        },
        {
            "@type": "xsd:string",
            "@value": "BB8"
        }
    ],
    "label": null,
    "person": null
}

Notice how each result is a flat array of values, not nested arrays. To make this into individual solutions, use the member operator: member(v.member, v.group), which will expand the group array into individual elements in the v.member variable.

Multiple Variable Template (Array of Tuples)

When grouping multiple variables, the template produces an array of tuples:

Example: JavaScript
let v = Vars("person", "label", "eyes", "group");
limit(1)
.group_by(
  "eyes",
  ["label", "eyes"],
  v.group,
  and(triple(v.person, "rdf:type", "@schema:People"),
      triple(v.person, "label", v.label),
      triple(v.person, "eye_color", v.eyes)))

Now the template ["label", "eyes"] includes two variables, so each result will be a tuple (array) containing both values:

Example: JSON
{
    "eyes": {
        "@type": "xsd:string",
        "@value": "black"
    },
    "group": [
        [
            {
                "@type": "xsd:string",
                "@value": "Greedo"
            },
            {
                "@type": "xsd:string",
                "@value": "black"
            }
        ],
        [
            {
                "@type": "xsd:string",
                "@value": "Nien Nunb"
            },
            {
                "@type": "xsd:string",
                "@value": "black"
            }
        ],
        [
            {
                "@type": "xsd:string",
                "@value": "Gasgano"
            },
            {
                "@type": "xsd:string",
                "@value": "black"
            }
        ],
        [
            {
                "@type": "xsd:string",
                "@value": "Kit Fisto"
            },
            {
                "@type": "xsd:string",
                "@value": "black"
            }
        ],
        [
            {
                "@type": "xsd:string",
                "@value": "Plo Koon"
            },
            {
                "@type": "xsd:string",
                "@value": "black"
            }
        ]
    ],
    "label": null,
    "person": null
}

Each element in the group array is now a tuple [label, eyes] containing both values.

Was this helpful?