Manage using API

Aggregates can be programmatically managed. Prerequisite is to have an API key with permissions allowing aggregate module operations. Dashboard and API key wizard can be used to quickly create such API key as explained in Manage using dashboard. Such API key might have following permissions:

Path Methods ACL
/aggregates/core\.aggregate/[0-9a-fA-F]{24} POST, PATCH, DELETE off
/aggregates/core\.aggregate GET, POST off

Create

The aggregate document is of type core.aggregate and must contain attributes:

  • input-type - name of an input type
  • output-type - name of an output type
  • pipeline - array containing pipeline stages

Example of an API request creating an aggregate:

curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "core.aggregate",
    "attributes": {
      "input-type": "message",
      "output-type": "agt.unread-message-summary",
      "pipeline": [{
        "filter": {
          "unread": { "$ne": false }
        }
      }, {
        "group": {
          "id": "$recipient.id",
          "unread-count": { "$sum": 1 }
        }
      }]
    }
  }
}' \
-X POST https://api.jazer.io/aggregates/core.aggregate

Created aggregate produces output collection containing exactly one document per recipient stating how many messages are unread in its inbox.

Note

During aggregate document creation only static analysis is performed against a pipeline. Some errors might not be visible until the runtime execution triggered by e.g. read AGT or search AGT.

Read

Fetching aggregate by ID is achievable with an API request:

curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/aggrebates/core.aggregate/<AGGREGATE_ID>

Update

Example API request updating an aggregate:

curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "core.aggregate",
    "id": "<AGGREGATE_ID>",
    "attributes": {
      "output-type": "agt.recipient-message-overview"
    }
  }
}' \
-X PATCH https://api.jazer.io/aggregates/core.aggregate/<AGGREGATE_ID>

Old output-type collection is destroyed and new collection is created using new output-type name.

Delete

To remove an aggregate use following API request:

curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X DELETE https://api.jazer.io/aggregates/core.aggregate/<AGGREGATE_ID>

The collection under output-type name will no longer be available after an aggregate is deleted.

Example

Prerequisite to test following examples is to have an API key with permissions:

Path Methods ACL
/resources/category POST off
/resources/product POST off
/aggregates/core\.aggregate POST off
/aggregates/agt\.product\.category\.statistics GET off
/aggregates/agt\.product\.category\.statistics/[0-9a-fA-F]{24} GET off

Test model consists of peristed types category and product.

An API request creating one category document:

curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "category",
    "attributes": {
      "name": "Motorcycles"
    }
  }
}' \
-X POST https://api.jazer.io/resources/category

API requests creating two product documents linking previously created category:

curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "product",
    "attributes": {
      "name": "Suzuki GSX-R750",
      "price": 10000
    },
    "relationships": {
      "category": {
        "data": {
          "type": "category",
          "id": "<CATEGORY_ID>"
        }
      }
    }
  }
}' \
-X POST https://api.jazer.io/resources/product
curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "product",
    "attributes": {
      "name": "Kawasaki Ninja ZX-6R",
      "price": 8000
    },
    "relationships": {
      "category": {
        "data": {
          "type": "category",
          "id": "<CATEGORY_ID>"
        }
      }
    }
  }
}' \
-X POST https://api.jazer.io/resources/product

An API request creating an aggregate for product category statistics:

curl -H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-d '
{
  "data": {
    "type": "core.aggregate",
    "attributes": {
      "input-type": "product",
      "output-type": "agt.product.category.statistics",
      "pipeline": [{
        "group": {
          "id": "$category.id",
          "minimum-price": { "$min": "$price" },
          "average-price": { "$avg": "$price" },
          "maximum-price": { "$max": "$price" },
          "product-count": { "$sum": 1 }
        }
      }]
    }
  }
}' \
-X POST https://api.jazer.io/aggregates/core.aggregate

Performing search AGT using agt.product.category.statistics type will contain documents where document IDs are equal to persisted category document IDs and attributes with accumulated values for product documents in that category. An API example performing basic search AGT is:

curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/aggregates/agt.product.category.statistics

The response contains agt.product.category.statistics documents:

{
  "meta": {
    "count": 1
  },
  "data": [
    {
      "type": "agt.product.category.statistics",
      "id": "5ba40d48ac6105131ff1d1d3",
      "attributes": {
        "minimum-price": 8000,
        "average-price": 9000,
        "maximum-price": 10000,
        "product-count": 2
      },
      "links": {
        "self": "https://api.jazer.io/aggregates/agt.product.category.statistics/5ba40d48ac6105131ff1d1d3"
      }
    }
  ],
  "links": {
    "first": "https://api.jazer.io/aggregates/agt.product.category.statistics?page[offset]=0&page[limit]=20",
    "last": "https://api.jazer.io/aggregates/agt.product.category.statistics?page[offset]=0&page[limit]=20",
    "prev": null,
    "next": null
  }
}

Since there is only one category document, there will be only one agt.product.category.statistics document. The response shows each document in AGT collection having its own hosting link. In other words, one can fetch document by ID. In this case pipeline constructs documents with IDs equal to category IDs, therefore only category ID must be known to fetch its corresponding agt.product.category.statistics document.

To fetch agt.product.category.statistics document for some category following API request can be used:

curl -H 'Accept: application/vnd.api+json' \
-H 'api-key: <YOUR_API_KEY_SECURE_ID>' \
-H 'application-id: <YOUR_APPLICATION_ID>' \
-X GET https://api.jazer.io/aggregates/agt.product.category.statistics/<CATEGORY_ID>

The response contains agt.product.category.statistics document with ID 5ba40d48ac6105131ff1d1d3:

{
  "data": {
    "type": "agt.product.category.statistics",
    "id": "5ba40d48ac6105131ff1d1d3",
    "attributes": {
      "minimum-price": 8000,
      "average-price": 9000,
      "maximum-price": 10000,
      "product-count": 2
    },
    "links": {
      "self": "https://api.jazer.io/aggregates/agt.product.category.statistics/5ba40d48ac6105131ff1d1d3"
    }
  }
}

In a lot of ways AGT documents are like persisted documents. They have a type and an unique ID. A hosting collection and a document endpoint. They can be used in relationships, e.g. product document could have relationship category-statistics containing link to an agt.product.category.statistics document. Such relationships support document inclusion. One API request can fetch product document and linked agt.product.category.statistics document.

Visit Read AGT and Search AGT for more information regarding features supported by AGT collections.