SlicingDice Documentation

SlicingDice API Docs

Welcome to the SlicingDice API documentation. You'll find comprehensive guides and documentation to help you start working with SlicingDice as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    Guides

How to make queries

First time checking our docs? You might want to start with the right foot by reading our Documentation Guide first.


Introduction

Querying is the action of manipulating data stored at SlicingDice in order to generate insights. Queries can be used either for analysis purposes or for retrieving stored data.

on the API-based JSON endpoint every query has its own endpoint under the common /query URL. Note that each query has its own syntax that must be followed to generate a correct request.

See below the similarity of a SQL query and the equivalent JSON for SlicingDice:

SQL query
SlicingDice query (JSON)
SELECT COUNT(*) 
FROM users 
WHERE 
name = 'Jeff';
{
    "query": [{
        "name": {"equals": "Jeff"}
    }],
    "dimension": "users"
}

Query types, operators, predicates and parameters

SlicingDice supports almost every query you would do on a relational database. Check out the supported queries page to see the full list of all queries we can make.

Making boolean queries on SlicingDice is also very easy, just check all the query operators page to get a detailed overview on how to use the and, or, not and freqgroup operators for the API-based JSON endpoint. Also check the operator precedence to understand how operators are considered in a query.

In the API-based JSON endpoint we support many query predicate, such as equals, not-equals, range, greater-than and much more. They are all listed and detailed in the query predicate page.


JOIN support out of the box

As you know, JOINs can be heavy and slow on normal databases, but not on SlicingDice.

SlicingDice was built to store attribute and event data in the same dimension, without forcing you to create different dimensions to split your attribute and event data.

Because of that, JOINs are performed out of the box on SlicingDice, without you even noticing it. Every time you make a query that uses an attribute and an event column on the same request, like the query below, a JOIN is transparently happening, but very fast.

Check our JOIN support page to learn more.

{
    "query": [
        {
            "name": { "equals": "Jeff" }
        },
        "and",
        {
            "clicks": {
                "equals": "Add to Cart",
                "between": [
                    "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-20d' %}", 
                    "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                ]
            }
        }
    ],
    "dimension": "users"
}

Querying data

In order to query data stored on SlicingDice, you only need to send a SELECT statement if you're using a SQL Driver or if you're using the API-based endpoints a POST request to https://api.slicingdice.com/v1/query with a JSON object according to the type of query you want to make. Visit the supported queries page to check all query types.

Pro Tip

Remember that you can also use test projects to make data insertions and queries before inserting real data to your production database.

Imagine you have this dimension data below stored on SlicingDice. Here we have one entity (UUID-01), using three columns, of which two of them are attribute columns (Name and Age) and one is an event column (Clicks).

User ID
Name
Age
Clicks

UUID-01

Jeff

25

Add to Cart - {% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}
Pay Now - {% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}
Support - {% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}

INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], [clicks.2.value], [clicks.2.date], name, age) VALUES ("UUID-01", "Add to Cart", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}", "Support", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}", "Jeff", 25);
$ curl -X POST https://api.slicingdice.com/v1/sql \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/sql' \
    -d 'INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], [clicks.2.value], [clicks.2.date], name, age) VALUES ("UUID-01", "Add to Cart", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}", "Support", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}", "Jeff", 25);'
curl -X POST https://api.slicingdice.com/v1/insert \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
        "UUID-01": {
            "name": "Jeff",
            "age": 25,
            "clicks": [
                {
                    "value": "Add to Cart",
                    "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}"
                }, {
                    "value": "Pay Now",
                    "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}"
                }, {
                    "value": "Support",
                    "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}"
                }
            ],
            "dimension": "users"
        },
        "auto-create": ["dimension", "column"]
    }'
from pyslicer import SlicingDice
slicingdice = SlicingDice(master_key='MASTER_API_KEY', uses_test_endpoint=True)

insert_data = {
    "UUID-01": {
        "dimension": "users",
        "age": 25,
        "name": "Jeff",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value": "Add to Cart"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value": "Pay Now"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value": "Support"
            }
        ]
    },
    "auto-create": [
        "dimension", 
        "column"
    ]
}

print(slicingdice.insert(insert_data))

import com.slicingdice.jslicer.SlicingDice;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONArray;

public class Example {
    public static void main(String[] args) throws IOException {
        SlicingDice slicingdice = new SlicingDice("MASTER_API_KEY", true);

        JSONObject insertData = new JSONObject()
        .put("UUID-01", new JSONObject()
            .put("dimension", "users")
            .put("age", 25)
            .put("name", "Jeff")
            .put("clicks", new JSONArray()
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}")
                    .put("value", "Add to Cart"))
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}")
                    .put("value", "Pay Now"))
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}")
                    .put("value", "Support"))))
        .put("auto-create", new JSONArray()
            .put("dimension")
            .put("column"));

        JSONObject result = slicingdice.insert(insertData);
        System.out.println(result.toString());
    }
}
require 'rbslicer'
slicingdice = SlicingDice.new(master_key: 'MASTER_API_KEY', uses_test_endpoint: true)

insert_data = {
    "UUID-01" => {
        "dimension" => "users",
        "age" => 25,
        "name" => "Jeff",
        "clicks" => [
            {
                "date" => "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value" => "Add to Cart"
            }, 
            {
                "date" => "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value" => "Pay Now"
            }, 
            {
                "date" => "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value" => "Support"
            }
        ]
    },
    "auto-create" => [
        "dimension", 
        "column"
    ]
}

puts slicingdice.insert(insert_data)

const SlicingDice = require('slicerjs');

const usesTestEndpoint = true;
const slicingdice = new SlicingDice({masterKey: 'MASTER_API_KEY'}, usesTestEndpoint);

const insertData = {
    "UUID-01": {
        "dimension": "users",
        "age": 25,
        "name": "Jeff",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value": "Add to Cart"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value": "Pay Now"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value": "Support"
            }
        ]
    },
    "auto-create": [
        "dimension", 
        "column"
    ]
};

slicingdice.insert(insertData).then((resp) => {
    console.log(resp);
}, (err) => {
    console.error(err);
});

<?php
use Slicer\SlicingDice;
$usesTestEndpoint = true;
$slicingdice = new SlicingDice(array("masterKey" => "MASTER_API_KEY"), $usesTestEndpoint);

$insertData = array(
    "UUID-01" => array(
        "dimension" => "users",
        "age" => 25,
        "name" => "Jeff",
        "clicks" => array(
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value" => "Add to Cart"
            ), 
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value" => "Pay Now"
            ), 
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value" => "Support"
            )
        )
    ),
    "auto-create" => array(
        "dimension", 
        "column"
    )
);

print_r($slicingdice->insert($insertData));
?>
using System.Collections.Generic;
using Slicer;
using Newtonsoft.Json;

namespace SlicerTester.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            var slicingdice = new SlicingDice(masterKey: "MASTER_API_KEY", usesTestEndpoint: true);

            var insertData = new Dictionary<string, dynamic>{
                {"UUID-01", new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"age", 25},
                    {"name", "Jeff"},
                    {"clicks", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}"},
                            {"value", "Add to Cart"}
                        }, 
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}"},
                            {"value", "Pay Now"}
                        }, 
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}"},
                            {"value", "Support"}
                        }
                    }}
                }},
                {"auto-create", new List<dynamic>{
                    "dimension", 
                    "column"
                }}
            };

            var result = slicingdice.Insert(insertData);
            System.Console.WriteLine(JsonConvert.SerializeObject(result).ToString());
        }
    }
}
package main
import (
    "fmt"
    "github.com/SlicingDice/slicingdice-go/slicingdice"
)
func main() {
    keys := new(slicingdice.APIKey)
    keys.MasterKey = "MASTER_API_KEY"
    slicingdice := slicingdice.New(keys, 60)
    slicingdice.Test = true

    insertData := map[string]interface{}{
        "UUID-01": map[string]interface{}{
            "dimension": "users",
            "age": 25,
            "name": "Jeff",
            "clicks": []interface{}{
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                    "value": "Add to Cart",
                },
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                    "value": "Pay Now",
                },
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                    "value": "Support",
                },
            },
        },
        "auto-create": []interface{}{
            "dimension",
            "column",
        },
    }

    fmt.Println(slicingdice.Insert(insertData))
}

Making a total query

First, let's check how many entities you have stored on your users dimension. In order to do that, you need to SELECT COUNT(*) on the SQL or make a request to /count/entity/total endpoint, like this query below.

SELECT COUNT(*) FROM users;
$ curl -X POST https://api.slicingdice.com/v1/sql \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/sql' \
    -d 'SELECT COUNT(*) FROM users;'
curl -X POST https://api.slicingdice.com/v1/query/count/entity/total \
    -H 'Authorization: MASTER_OR_READ_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
        "dimension": "users"
    }'
from pyslicer import SlicingDice
slicingdice = SlicingDice(master_key='MASTER_API_KEY', uses_test_endpoint=True)

query_data = [
    "users"
]

print(slicingdice.count_entity_total(query_data))
import com.slicingdice.jslicer.SlicingDice;
import java.io.IOException;
import org.json.JSONObject;
import java.util.ArrayList;

public class Example {
    public static void main(String[] args) throws IOException {
        SlicingDice slicingdice = new SlicingDice("MASTER_API_KEY", true);
        
        ArrayList<String> queryData = new ArrayList<>();
        queryData.add("users");
      
        JSONObject result = slicingdice.countEntityTotal(queryData);
        System.out.println(result.toString());
    }
}
require 'rbslicer'
slicingdice = SlicingDice.new(master_key: 'MASTER_API_KEY', uses_test_endpoint: true)

query_data = [
    "users"
]

puts slicingdice.count_entity_total(query_data)

const SlicingDice = require('slicerjs');

const usesTestEndpoint = true;
const slicingdice = new SlicingDice({masterKey: 'MASTER_API_KEY'}, usesTestEndpoint);

const queryData = [
    "users"
];

slicingdice.countEntityTotal(queryData).then((resp) => {
    console.log(resp);
}, (err) => {
    console.error(err);
});

<?php
use Slicer\SlicingDice;
$usesTestEndpoint = true;
$slicingdice = new SlicingDice(array("masterKey" => "MASTER_API_KEY"), $usesTestEndpoint);

$queryData = array(
    "users"
);

print_r($slicingdice->countEntityTotal($queryData));
?>
using System.Collections.Generic;
using Slicer;
using Newtonsoft.Json;

namespace SlicerTester.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            var slicingdice = new SlicingDice(masterKey: "MASTER_API_KEY", usesTestEndpoint: true);

            var queryData = new List<string>{
                "users"
            };

            var result = slicingdice.CountEntityTotal(queryData);
            System.Console.WriteLine(JsonConvert.SerializeObject(result).ToString());
        }
    }
}
package main
import (
    "fmt"
    "github.com/SlicingDice/slicingdice-go/slicingdice"
)
func main() {
    keys := new(slicingdice.APIKey)
    keys.MasterKey = "MASTER_API_KEY"
    slicingdice := slicingdice.New(keys, 60)
    slicingdice.Test = true

    queryData := []string{
        "users",
    }

    fmt.Println(slicingdice.CountEntityTotal(queryData))
}

After making this query above, if you're using the API-based JSON endpoint the API response will be in the format below:

{
    "status": "success",
    "result": {
        "total": 1
    },
    "took": 0.103
}

Let's understand each component of the API response:

  • status - Indicating whether the request was successfully processed or not.
  • result - Query data.
  • total - Total number of entities stored in the dimension.
  • took - Time spent processing this request, in seconds.

Making a count entities query

Now, using the same data above, let's count how many unique entities there are on the dimension users that have the name column equals to "Jeff" and age column equals to 25. In order to do that, you need to execute the query below using a SELECT COUNT(*) statement or the /count/entity endpoint.

SELECT COUNT(*) FROM users WHERE name = 'Jeff' AND age = 25;
$ curl -X POST https://api.slicingdice.com/v1/sql \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/sql' \
    -d 'SELECT COUNT(*) FROM users WHERE name = 'Jeff' AND age = 25;'
curl -X POST https://api.slicingdice.com/v1/query/count/entity \
    -H 'Authorization: MASTER_OR_READ_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '[
        {
            "dimension": "users",
            "query-name": "jeff-user-and-25-yo",
            "query": [
                {
                    "name": {
                        "equals": "Jeff"
                    }
                },
                "and",
                {
                    "age": {
                        "equals": "25"
                    }
                }
            ],
            "bypass-cache": true
        }
    ]'
from pyslicer import SlicingDice
slicingdice = SlicingDice(master_key='MASTER_API_KEY', uses_test_endpoint=True)

query_data = [
    {
        "dimension": "users",
        "query": [
            {
                "name": {
                    "equals": "Jeff"
                }
            }, 
            "and", 
            {
                "age": {
                    "equals": "25"
                }
            }
        ],
        "query-name": "jeff-user-and-25-yo",
        "bypass-cache": True
    }
]

print(slicingdice.count_entity(query_data))

import com.slicingdice.jslicer.SlicingDice;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONArray;

public class Example {
    public static void main(String[] args) throws IOException {
        SlicingDice slicingdice = new SlicingDice("MASTER_API_KEY", true);

        JSONArray queryData = new JSONArray()
        .put(new JSONObject()
            .put("dimension", "users"))
            .put("query", new JSONArray()
                .put(new JSONObject()
                    .put("name", new JSONObject()
                        .put("equals", "Jeff")))
                .put("and")
                .put(new JSONObject()
                    .put("age", new JSONObject()
                        .put("equals", "25"))))
            .put("query-name", "jeff-user-and-25-yo")
            .put("bypass-cache", true);
        JSONObject result = slicingdice.countEntity(queryData);
        System.out.println(result.toString());
    }
}
require 'rbslicer'
slicingdice = SlicingDice.new(master_key: 'MASTER_API_KEY', uses_test_endpoint: true)

query_data = [
    {
        "dimension" => "users",
        "query" => [
            {
                "name" => {
                    "equals" => "Jeff"
                }
            }, 
            "and", 
            {
                "age" => {
                    "equals" => "25"
                }
            }
        ],
        "query-name" => "jeff-user-and-25-yo",
        "bypass-cache" => true
    }
]

puts slicingdice.count_entity(query_data)

const SlicingDice = require('slicerjs');

const usesTestEndpoint = true;
const slicingdice = new SlicingDice({masterKey: 'MASTER_API_KEY'}, usesTestEndpoint);

const queryData = [
    {
        "dimension": "users",
        "query": [
            {
                "name": {
                    "equals": "Jeff"
                }
            }, 
            "and", 
            {
                "age": {
                    "equals": "25"
                }
            }
        ],
        "query-name": "jeff-user-and-25-yo",
        "bypass-cache": true
    }
];

slicingdice.countEntity(queryData).then((resp) => {
    console.log(resp);
}, (err) => {
    console.error(err);
});

<?php
use Slicer\SlicingDice;
$usesTestEndpoint = true;
$slicingdice = new SlicingDice(array("masterKey" => "MASTER_API_KEY"), $usesTestEndpoint);

$queryData = array(
    array(
        "dimension" => "users",
        "query" => array(
            array(
                "name" => array(
                    "equals" => "Jeff"
                )
            ), 
            "and", 
            array(
                "age" => array(
                    "equals" => "25"
                )
            )
        ),
        "query-name" => "jeff-user-and-25-yo",
        "bypass-cache" => true
    )
);

print_r($slicingdice->countEntity($queryData));
?>
using System.Collections.Generic;
using Slicer;
using Newtonsoft.Json;

namespace SlicerTester.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            var slicingdice = new SlicingDice(masterKey: "MASTER_API_KEY", usesTestEndpoint: true);

            var queryData = new List<dynamic>{
                new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"query", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"name", new Dictionary<string, dynamic>{
                                {"equals", "Jeff"}
                            }}
                        }, 
                        "and", 
                        new Dictionary<string, dynamic>{
                            {"age", new Dictionary<string, dynamic>{
                                {"equals", "25"}
                            }}
                        }
                    }},
                    {"query-name", "jeff-user-and-25-yo"},
                    {"bypass-cache", true}
                }
            };

            var result = slicingdice.CountEntity(queryData);
            System.Console.WriteLine(JsonConvert.SerializeObject(result).ToString());
        }
    }
}
package main
import (
    "fmt"
    "github.com/SlicingDice/slicingdice-go/slicingdice"
)
func main() {
    keys := new(slicingdice.APIKey)
    keys.MasterKey = "MASTER_API_KEY"
    slicingdice := slicingdice.New(keys, 60)
    slicingdice.Test = true

    queryData := []interface{}{
        map[string]interface{}{
            "dimension": "users",
            "query": []interface{}{
                map[string]interface{}{
                    "name": map[string]interface{}{
                        "equals": "Jeff",
                    },
                },
                "and",
                map[string]interface{}{
                    "age": map[string]interface{}{
                        "equals": "25",
                    },
                },
            },
            "query-name": "jeff-user-and-25-yo",
            "bypass-cache": true,
        },
    }

    fmt.Println(slicingdice.CountEntity(queryData))
}

If you're using the API-based JSON endpoint the API response for this query above will be in the format below:

{
    "status": "success",
    "result": {
        "jeff-user-and-25-yo": 1
    },
    "took": 0.103
}

Let's understand each component of the API response:

  • status - Indicating whether the request was successfully processed or not.
  • result - Query name (jeff-user-and-25-yo) and the total number of entities that matches all query conditions (1).
  • took - Time spent processing this request, in seconds.

Querying attribute and event columns

Before explaining the difference between attribute and event columns, as data and code is worth more than 1,000 words, please take a look on this data table below:

User ID
Name
Age
Clicks

UUID-01

Jeff

25

Add to Cart - {% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}
Pay Now - {% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}
Support - {% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}

UUID-02

Michelle

32

Pay Now - {% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}

UUID-03

Lerry

47

Support - {% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}
Pay Now - {% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}

INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], [clicks.2.value], [clicks.2.date], name, age) VALUES ("UUID-01", "Add to Cart", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}", "Support", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}", "Jeff", 25);
INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], name, age) VALUES ("UUID-02", "Pay Now", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}", "Michelle", 32);
INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], name, age) VALUES ("UUID-03", "Support", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}", "Lerry", 47);
$ curl -X POST https://api.slicingdice.com/v1/sql \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/sql' \
    -d 'INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], [clicks.2.value], [clicks.2.date], name, age) VALUES ("UUID-01", "Add to Cart", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}", "Support", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}", "Jeff", 25); INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], name, age) VALUES ("UUID-02", "Pay Now", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}", "Michelle", 32); INSERT INTO users ([entity-id], [clicks.0.value], [clicks.0.date], [clicks.1.value], [clicks.1.date], name, age) VALUES ("UUID-03", "Support", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}", "Pay Now", "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}", "Lerry", 47);'
curl -X POST https://api.slicingdice.com/v1/insert \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{
        "UUID-01": {
            "dimension": "users",
            "name": "Jeff",
            "age": 25,
            "clicks": [
                {
                    "value": "Add to Cart",
                    "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}"
                }, {
                    "value": "Pay Now",
                    "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}"
                }, {
                    "value": "Support",
                    "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}"
                }
            ],
        },
        "UUID-02": {
            "dimension": "users",
            "name": "Michelle",
            "age": 32,
            "clicks": [
                {
                    "value": "Pay Now",
                    "date": "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}"
                }
            ]
        },
        "UUID-03": {
            "dimension": "users",
            "name": "Lerry",
            "age": 47,
            "clicks": [
                {
                    "value": "Support",
                    "date": "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}"
                }, {
                    "value": "Pay Now",
                    "date": "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}"
                }
            ]
        },
        "auto-create": ["dimension", "column"]
    }'
from pyslicer import SlicingDice
slicingdice = SlicingDice(master_key='MASTER_API_KEY', uses_test_endpoint=True)

insert_data = {
    "UUID-01": {
        "dimension": "users",
        "age": 25,
        "name": "Jeff",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value": "Add to Cart"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value": "Pay Now"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value": "Support"
            }
        ]
    },
    "UUID-03": {
        "dimension": "users",
        "age": 47,
        "name": "Lerry",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}",
                "value": "Support"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}",
                "value": "Pay Now"
            }
        ]
    },
    "UUID-02": {
        "dimension": "users",
        "age": 32,
        "name": "Michelle",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}",
                "value": "Pay Now"
            }
        ]
    },
    "auto-create": [
        "dimension", 
        "column"
    ]
}

print(slicingdice.insert(insert_data))

import com.slicingdice.jslicer.SlicingDice;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONArray;

public class Example {
    public static void main(String[] args) throws IOException {
        SlicingDice slicingdice = new SlicingDice("MASTER_API_KEY", true);

        JSONObject insertData = new JSONObject()
        .put("UUID-01", new JSONObject()
            .put("dimension", "users")
            .put("age", 25)
            .put("name", "Jeff")
            .put("clicks", new JSONArray()
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}")
                    .put("value", "Add to Cart"))
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}")
                    .put("value", "Pay Now"))
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}")
                    .put("value", "Support"))))
        .put("UUID-03", new JSONObject()
            .put("dimension", "users")
            .put("age", 47)
            .put("name", "Lerry")
            .put("clicks", new JSONArray()
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}")
                    .put("value", "Support"))
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}")
                    .put("value", "Pay Now"))))
        .put("UUID-02", new JSONObject()
            .put("dimension", "users")
            .put("age", 32)
            .put("name", "Michelle")
            .put("clicks", new JSONArray()
                .put(new JSONObject()
                    .put("date", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}")
                    .put("value", "Pay Now"))))
        .put("auto-create", new JSONArray()
            .put("dimension")
            .put("column"));

        JSONObject result = slicingdice.insert(insertData);
        System.out.println(result.toString());
    }
}
require 'rbslicer'
slicingdice = SlicingDice.new(master_key: 'MASTER_API_KEY', uses_test_endpoint: true)

insert_data = {
    "UUID-01" => {
        "dimension" => "users",
        "age" => 25,
        "name" => "Jeff",
        "clicks" => [
            {
                "date" => "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value" => "Add to Cart"
            }, 
            {
                "date" => "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value" => "Pay Now"
            }, 
            {
                "date" => "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value" => "Support"
            }
        ]
    },
    "UUID-03" => {
        "dimension" => "users",
        "age" => 47,
        "name" => "Lerry",
        "clicks" => [
            {
                "date" => "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}",
                "value" => "Support"
            }, 
            {
                "date" => "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}",
                "value" => "Pay Now"
            }
        ]
    },
    "UUID-02" => {
        "dimension" => "users",
        "age" => 32,
        "name" => "Michelle",
        "clicks" => [
            {
                "date" => "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}",
                "value" => "Pay Now"
            }
        ]
    },
    "auto-create" => [
        "dimension", 
        "column"
    ]
}

puts slicingdice.insert(insert_data)

const SlicingDice = require('slicerjs');

const usesTestEndpoint = true;
const slicingdice = new SlicingDice({masterKey: 'MASTER_API_KEY'}, usesTestEndpoint);

const insertData = {
    "UUID-01": {
        "dimension": "users",
        "age": 25,
        "name": "Jeff",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value": "Add to Cart"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value": "Pay Now"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value": "Support"
            }
        ]
    },
    "UUID-03": {
        "dimension": "users",
        "age": 47,
        "name": "Lerry",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}",
                "value": "Support"
            }, 
            {
                "date": "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}",
                "value": "Pay Now"
            }
        ]
    },
    "UUID-02": {
        "dimension": "users",
        "age": 32,
        "name": "Michelle",
        "clicks": [
            {
                "date": "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}",
                "value": "Pay Now"
            }
        ]
    },
    "auto-create": [
        "dimension", 
        "column"
    ]
};

slicingdice.insert(insertData).then((resp) => {
    console.log(resp);
}, (err) => {
    console.error(err);
});

<?php
use Slicer\SlicingDice;
$usesTestEndpoint = true;
$slicingdice = new SlicingDice(array("masterKey" => "MASTER_API_KEY"), $usesTestEndpoint);

$insertData = array(
    "UUID-01" => array(
        "dimension" => "users",
        "age" => 25,
        "name" => "Jeff",
        "clicks" => array(
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                "value" => "Add to Cart"
            ), 
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                "value" => "Pay Now"
            ), 
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                "value" => "Support"
            )
        )
    ),
    "UUID-03" => array(
        "dimension" => "users",
        "age" => 47,
        "name" => "Lerry",
        "clicks" => array(
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}",
                "value" => "Support"
            ), 
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}",
                "value" => "Pay Now"
            )
        )
    ),
    "UUID-02" => array(
        "dimension" => "users",
        "age" => 32,
        "name" => "Michelle",
        "clicks" => array(
            array(
                "date" => "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}",
                "value" => "Pay Now"
            )
        )
    ),
    "auto-create" => array(
        "dimension", 
        "column"
    )
);

print_r($slicingdice->insert($insertData));
?>
using System.Collections.Generic;
using Slicer;
using Newtonsoft.Json;

namespace SlicerTester.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            var slicingdice = new SlicingDice(masterKey: "MASTER_API_KEY", usesTestEndpoint: true);

            var insertData = new Dictionary<string, dynamic>{
                {"UUID-01", new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"age", 25},
                    {"name", "Jeff"},
                    {"clicks", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}"},
                            {"value", "Add to Cart"}
                        }, 
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}"},
                            {"value", "Pay Now"}
                        }, 
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}"},
                            {"value", "Support"}
                        }
                    }}
                }},
                {"UUID-03", new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"age", 47},
                    {"name", "Lerry"},
                    {"clicks", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}"},
                            {"value", "Support"}
                        }, 
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}"},
                            {"value", "Pay Now"}
                        }
                    }}
                }},
                {"UUID-02", new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"age", 32},
                    {"name", "Michelle"},
                    {"clicks", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"date", "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}"},
                            {"value", "Pay Now"}
                        }
                    }}
                }},
                {"auto-create", new List<dynamic>{
                    "dimension", 
                    "column"
                }}
            };

            var result = slicingdice.Insert(insertData);
            System.Console.WriteLine(JsonConvert.SerializeObject(result).ToString());
        }
    }
}
package main
import (
    "fmt"
    "github.com/SlicingDice/slicingdice-go/slicingdice"
)
func main() {
    keys := new(slicingdice.APIKey)
    keys.MasterKey = "MASTER_API_KEY"
    slicingdice := slicingdice.New(keys, 60)
    slicingdice.Test = true

    insertData := map[string]interface{}{
        "UUID-01": map[string]interface{}{
            "dimension": "users",
            "age": 25,
            "name": "Jeff",
            "clicks": []interface{}{
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT12:54:12Z' '-10d' %}",
                    "value": "Add to Cart",
                },
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT10:22:10Z' '-5d' %}",
                    "value": "Pay Now",
                },
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT17:05:25Z' '-2d' %}",
                    "value": "Support",
                },
            },
        },
        "UUID-03": map[string]interface{}{
            "dimension": "users",
            "age": 47,
            "name": "Lerry",
            "clicks": []interface{}{
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT00:41:34Z' '-1d' %}",
                    "value": "Support",
                },
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT09:41:17Z' '-3d' %}",
                    "value": "Pay Now",
                },
            },
        },
        "UUID-02": map[string]interface{}{
            "dimension": "users",
            "age": 32,
            "name": "Michelle",
            "clicks": []interface{}{
                map[string]interface{}{
                    "date": "{% convert_date 'YYYY-MM-DDT16:21:16Z' '-4d' %}",
                    "value": "Pay Now",
                },
            },
        },
        "auto-create": []interface{}{
            "dimension",
            "column",
        },
    }

    fmt.Println(slicingdice.Insert(insertData))
}

Suppose you have this data above. As you can see, the Clicks column is storing event data, and the other columns are storing attributes, like Name and Age.

That's basically the difference between Attribute Columns and Event Columns:

  • Attribute Column is a column type used to store any data not associated to a date/time. Example: storing the value Jeff for the Name column and the value 25 for the Age column. In this case both columns and their values are not associated to a specific date/time.

  • Event Column is column type used to store data that is associated to a date/time. Example: storing the value Add to Cart on the date/time {% convert_date 'YYYY-MM-DDT00:00:00Z' '-10d' %} for the Click event column. In this case it's important to know when the Add to Cart event happened.

Check the docs for a detailed comparison on attribute and event columns.

Making count entity query with attribute and event columns

Let's make a query using the previous data table to count how many unique entities there are on the dimension users, that have the name attribute column equals to Jeff and clicks event column equals to Pay Now between {% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %} and {% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}. In order get the result for this query, you need to execute the query below using the SQL Driver or the /count/entity endpoint.

$ curl -X POST https://api.slicingdice.com/v1/sql \
    -H 'Authorization: MASTER_OR_WRITE_API_KEY' \
    -H 'Content-Type: application/sql' \
    -d 'SELECT COUNT([entity-id]) FROM users WHERE name = 'Jeff' AND [clicks.value] = 'Pay Now' and [clicks.date] BETWEEN '{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}' AND '{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}';'
curl -X POST https://api.slicingdice.com/v1/query/count/entity \
    -H 'Authorization: MASTER_OR_READ_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '[
        {
            "dimension": "users",
            "query-name": "jeff-user-clicked-to-pay",
            "query": [
                {
                    "name": {
                        "equals": "Jeff"
                    }
                },
                "and",
                {
                    "clicks": {
                        "equals": "Pay Now",
                        "between": [
                            "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}",
                            "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                        ]
                    }
                }
            ],
            "bypass-cache": true
        }
    ]'
from pyslicer import SlicingDice
slicingdice = SlicingDice(master_key='MASTER_API_KEY', uses_test_endpoint=True)

query_data = [
    {
        "dimension": "users",
        "query": [
            {
                "name": {
                    "equals": "Jeff"
                }
            }, 
            "and", 
            {
                "clicks": {
                    "equals": "Pay Now",
                    "between": [
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}", 
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                    ]
                }
            }
        ],
        "query-name": "jeff-user-clicked-to-pay",
        "bypass-cache": True
    }
]

print(slicingdice.count_entity(query_data))

import com.slicingdice.jslicer.SlicingDice;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONArray;

public class Example {
    public static void main(String[] args) throws IOException {
        SlicingDice slicingdice = new SlicingDice("MASTER_API_KEY", true);

        JSONArray queryData = new JSONArray()
        .put(new JSONObject()
            .put("dimension", "users"))
            .put("query", new JSONArray()
                .put(new JSONObject()
                    .put("name", new JSONObject()
                        .put("equals", "Jeff")))
                .put("and")
                .put(new JSONObject()
                    .put("clicks", new JSONObject()
                        .put("equals", "Pay Now")
                        .put("between", new JSONArray()
                            .put("{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}")
                            .put("{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}")))))
            .put("query-name", "jeff-user-clicked-to-pay")
            .put("bypass-cache", true);
        JSONObject result = slicingdice.countEntity(queryData);
        System.out.println(result.toString());
    }
}
require 'rbslicer'
slicingdice = SlicingDice.new(master_key: 'MASTER_API_KEY', uses_test_endpoint: true)

query_data = [
    {
        "dimension" => "users",
        "query" => [
            {
                "name" => {
                    "equals" => "Jeff"
                }
            }, 
            "and", 
            {
                "clicks" => {
                    "equals" => "Pay Now",
                    "between" => [
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}", 
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                    ]
                }
            }
        ],
        "query-name" => "jeff-user-clicked-to-pay",
        "bypass-cache" => true
    }
]

puts slicingdice.count_entity(query_data)

const SlicingDice = require('slicerjs');

const usesTestEndpoint = true;
const slicingdice = new SlicingDice({masterKey: 'MASTER_API_KEY'}, usesTestEndpoint);

const queryData = [
    {
        "dimension": "users",
        "query": [
            {
                "name": {
                    "equals": "Jeff"
                }
            }, 
            "and", 
            {
                "clicks": {
                    "equals": "Pay Now",
                    "between": [
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}", 
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                    ]
                }
            }
        ],
        "query-name": "jeff-user-clicked-to-pay",
        "bypass-cache": true
    }
];

slicingdice.countEntity(queryData).then((resp) => {
    console.log(resp);
}, (err) => {
    console.error(err);
});

<?php
use Slicer\SlicingDice;
$usesTestEndpoint = true;
$slicingdice = new SlicingDice(array("masterKey" => "MASTER_API_KEY"), $usesTestEndpoint);

$queryData = array(
    array(
        "dimension" => "users",
        "query" => array(
            array(
                "name" => array(
                    "equals" => "Jeff"
                )
            ), 
            "and", 
            array(
                "clicks" => array(
                    "equals" => "Pay Now",
                    "between" => array(
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}", 
                        "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                    )
                )
            )
        ),
        "query-name" => "jeff-user-clicked-to-pay",
        "bypass-cache" => true
    )
);

print_r($slicingdice->countEntity($queryData));
?>
using System.Collections.Generic;
using Slicer;
using Newtonsoft.Json;

namespace SlicerTester.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            var slicingdice = new SlicingDice(masterKey: "MASTER_API_KEY", usesTestEndpoint: true);

            var queryData = new List<dynamic>{
                new Dictionary<string, dynamic>{
                    {"dimension", "users"},
                    {"query", new List<dynamic>{
                        new Dictionary<string, dynamic>{
                            {"name", new Dictionary<string, dynamic>{
                                {"equals", "Jeff"}
                            }}
                        }, 
                        "and", 
                        new Dictionary<string, dynamic>{
                            {"clicks", new Dictionary<string, dynamic>{
                                {"equals", "Pay Now"},
                                {"between", new List<dynamic>{
                                    "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}", 
                                    "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}"
                                }}
                            }}
                        }
                    }},
                    {"query-name", "jeff-user-clicked-to-pay"},
                    {"bypass-cache", true}
                }
            };

            var result = slicingdice.CountEntity(queryData);
            System.Console.WriteLine(JsonConvert.SerializeObject(result).ToString());
        }
    }
}
package main
import (
    "fmt"
    "github.com/SlicingDice/slicingdice-go/slicingdice"
)
func main() {
    keys := new(slicingdice.APIKey)
    keys.MasterKey = "MASTER_API_KEY"
    slicingdice := slicingdice.New(keys, 60)
    slicingdice.Test = true

    queryData := []interface{}{
        map[string]interface{}{
            "dimension": "users",
            "query": []interface{}{
                map[string]interface{}{
                    "name": map[string]interface{}{
                        "equals": "Jeff",
                    },
                },
                "and",
                map[string]interface{}{
                    "clicks": map[string]interface{}{
                        "equals": "Pay Now",
                        "between": []interface{}{
                            "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %}",
                            "{% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}",
                        },
                    },
                },
            },
            "query-name": "jeff-user-clicked-to-pay",
            "bypass-cache": true,
        },
    }

    fmt.Println(slicingdice.CountEntity(queryData))
}

If you're using the API-based JSON endpoint the API response for this query above will be in the format below:

{
    "status": "success",
    "result": {
        "jeff-user-clicked-to-pay": 1
    },
    "took": 0.103
}

As you can see, there is just one entity that has Jeff value in the name attribute column and that also has the value Pay Now for the Clicks event column between the dates {% convert_date 'YYYY-MM-DDT00:00:00Z' '-15d' %} and {% convert_date 'YYYY-MM-DDT00:00:00Z' '-1d' %}.



How to make queries

First time checking our docs? You might want to start with the right foot by reading our Documentation Guide first.