# Aggregations

Jump to the [Code block](#code-block) for a combined complete example.

A common way to process the results of a [basic query](https://aerospike.com/docs/develop/client/node/usage/multi/queries/basic) is aggregation, where you compute a function over the entire results set.

## Setup

The following examples use the following setup to illustrate query aggregation with a stream UDF.

```js
const Aerospike = await import("aerospike");
```

The record structure:

```asciidoc
Occurred: Integer

Reported: Integer

Posted: Integer

Report: Map

{

    shape: List,

    summary: String,

    city: String,

    state: String,

    duration: String

}

Location: GeoJSON
```

## Stream UDF

When a query executes, it produces a stream of results. That stream contains records that you can iterate using the client API. However, Aerospike provides the ability to process the stream of results using a Stream UDF. Stream UDFs allow a stream to be augmented with operations that process the data flowing through the stream.

This example uses the Stream UDF `count`, from the `example.lua` module. See Manage UDFs for information on registering the UDF.

```lua
-- Aggregation function to count records

local function one(rec)

    return 1

end

local function add(a, b)

    return a + b

end

function count(stream)

    return stream : map(one) : reduce(add);

end
```

`count()` is applied to the stream of results from a query, adding to the stream the operations to perform on the results:

-   `map` — Maps a value from the stream to another value. In this example, mapping is defined as the function `one()`, which maps a record to the value 1.
-   `reduce` — Reduces the values from the stream into a single value. In this example, reduction is performed by adding two values from the stream, which happen to be 1s returned from the `map` function.

The end result is a stream that contains a single value, the sum of 1 for each record in the result set.

## Client UDF path

For client-side Stream UDF processing, you must point the client to the local location of the UDF module.

```js
// Set hosts to your server's address and port and set modlua

const config = {

  hosts: "YOUR_HOST_ADDRESS:YOUR_PORT",

  // Set local directory

  modlua: { userPath: "/home/user/udf" },

};

// Establishes a connection to the server

const client = await Aerospike.connect(config);
```

## Execute the query

The following example will execute a [secondary index query](https://aerospike.com/docs/develop/client/node/usage/multi/queries/secondary), using an [index created](https://aerospike.com/docs/develop/client/node/usage/multi/queries/secondary#create-an-index) on the `occurred` bin. The returned result will be a count of all records with an `occurred` value between `20210101` and `20211231`.

```js
// Create query

const query = client.query("sandbox", "ufodata");

// Create the index filter

query.where(Aerospike.filter.range("occurred", 20220431, 20220631));

// Execute the query

const result = await query.apply("example", "count");

// Get result

console.info("Count = %o", result);
```

## Code block

Expand this section for a single code block to apply a stream UDF aggregation

```js
const Aerospike = await import("aerospike");

// Set hosts to your server's address and port and set modlua

const config = {

  hosts: "YOUR_HOST_ADDRESS:YOUR_PORT",

  // Set local directory

  modlua: { userPath: "/home/user/udf" },

};

// Establishes a connection to the server

const client = await Aerospike.connect(config);

// Create query

const query = client.query("sandbox", "ufodata");

// Create the index filter

query.where(Aerospike.filter.range("occurred", 20220431, 20220631));

// Execute the query

const result = await query.apply("example", "count");

// Get result

console.info("Count = %o", result);

await client.close();
```