Primary index
Jump to the Code block for a combined complete example.
Basic PI queries have the following features:
- Filter records by set name.
- Filter records by Filter Expressions.
- Limit the number of records returned, useful for pagination.
- Return only record digests and metadata (generation and TTL).
- Return specified bins.
Setup
The following examples will use the setup and record structure below to illustrate primary index queries in an Aerospike database.
const Aerospike = require('aerospike');const exp = Aerospike.exp;
// Define host configurationlet config = {hosts: '127.0.0.1:3000'};
The record structure:
Occurred: IntegerReported: IntegerPosted: IntegerReport: Map{ shape: List, summary: String, city: String, state: String, duration: String}Location: GeoJSON
Policies
See Basic Queries for query policy information.
Query a set
The following example queries the sandbox
namespace and ufodata
set name, while limiting the record set to only 20 records.
// Set max records to returnconst maxRecords = 20;let counter = 0;
// Create queryconst query = client.query("sandbox", "ufodata");
// Execute the queryconst recordStream = await query.foreach();
recordStream.on("error", (err) => { // Handle error console.log("query failed: " + err); recordStream.abort();});
recordStream.on("data", (record) => { // Handle data counter++; console.info("Record: %o", record.bins); if (counter === maxRecords) { recordStream.abort(); }});
recordStream.on("end", async () => { // Close the connection to the server await client.close();});
Query with a metadata filter
The following example queries the same namespace and set as the example above, but also adds a metadata Filter Expression that will only return records that are greater than 16 KiB.
// Create query policyconst queryPolicy = new Aerospike.QueryPolicy({ filterExpression: exp.gt(exp.deviceSize(), exp.int(1024 * 16)),});
// Create queryconst query = client.query("sandbox", "ufodata");
// Execute the queryconst recordStream = await query.foreach(queryPolicy);
recordStream.on("error", (err) => { // Handle error console.log("query failed: " + err); recordStream.abort();});recordStream.on("data", (record) => { // Handle data console.info("Record: %o", record.bins);});recordStream.on("end", async () => { // Close the connection to the server await client.close();});
Query with a data filter
The following example queries the same namespace and set as the example above, but also adds a data Filter Expression that
will only return records where the occurred
bin value is in the inclusive range 20200101
to 20211231
.
Take a look at secondary index queries to see how this same query can be run more efficiently with an index.
// Create query policyconst queryPolicy = new Aerospike.QueryPolicy({ filterExpression: exp.let( exp.def("bin", exp.binInt("occurred")), exp.and( exp.ge(exp.var("bin"), exp.int(20220431)), exp.le(exp.var("bin"), exp.int(20220631)), ), ),});
// Create queryconst query = client.query("test", "demo");
// Execute the queryconst recordStream = await query.foreach(queryPolicy);
recordStream.on("error", (err) => { console.log("query failed: " + err); recordStream.abort();});recordStream.on("data", (record) => { // handle record console.info("Record: %o\\n", record.bins);});recordStream.on("end", async () => { // Close the connection to the server await client.close();});
Pagination
Pagination uses a combination of a partition filter and a defined maximum records to return query results. The partition filter maintains a cursor identifying the end of the current page and the beginning of the next. Moving to the next page of results is as simple as executing the query again, with the previously defined partition filter.
The following example executes a query with an Expression Filter identifying records with more than 3 shape
items in the report
map,
returning 10 records per page. The partition filter is set to query all 4096 partitions in the database.
import { once } from "events";
// Create the expressionconst filterExpression = exp.gt( exp.lists.size( exp.maps.getByKey( exp.binMap("report"), "shape", exp.type.LIST, maps.returnType.VALUE, ), ), exp.int(3),);
// Create the policyconst queryPolicy = { filterExpression };
// Create the queryconst query = client.query("test", "demo");
// Set max recordsquery.maxRecords = 10;
// Set paginatequery.paginate = true;
let stream = query.foreach();
stream.on("error", (error) => { throw error;});
stream.on("data", (record) => { // handle data console.log(record.bins);});
let queryState = await once(stream, "end");
query.nextPage(queryState[0]);
// Check to see if any pages are leftif (query.hasNextPage()) { stream = query.foreach();} else { await client.close(); process.exit(0);}
stream.on("error", (error) => { throw error;});
stream.on("data", (record) => { // handle data console.log(record.bins);});
queryState = await once(stream, "end");
await client.close();
Code block
Expand this section for a single code block to execute a basic PI query
const Aerospike = await import("aerospike");const exp = Aerospike.exp;
// Set hosts to your server's address and port const config = { hosts: "YOUR_HOST_ADDRESS:YOUR_PORT" };
// Establishes a connection to the serverconst client = await Aerospike.connect(config);
// Create queryconst query = client.query("test", "demo");
// Execute the queryconst records = await query.results();
records.forEach((record) => { console.info("Record: %o", record.bins);});
await client.close();