Select
Select has only one argument, it's an optional array of columns and/or functions to apply to the query. Let's look at some examples.
Simple Select
// Get all rows from the users table.
nSQL("users").query("select").exec().then((rows) => {
console.log(rows) // <= array of row objects
});
// Get all rows, but only the username column.
nSQL("users").query("select",["username"]).exec().then..
// Get username column and return it as name, then also get the age column.
nSQL("users").query("select",["username AS name","age"]).exec().then...
// Apply an aggregate function to the query...
nSQL("users").query("select",["COUNT(*) AS totalUsers"]).exec().then...
nSQL("users").query("select",["AVG(age) AS averageAge"]).exec().then..
// Query against properties of a column
nSQL("users").query("select").where(["posts.length", ">", 3]).exec().then...
nSQL("users").query("select").where(["meta.eyeColor", "=", "blue"]).exec().then...
nSQL("users").query("select", ["AVG(posts.length) AS averagePostCount"]).exec().then...
The built in functions include COUNT, MAX, MIN, GREATEST, LEAST, AVG, SUM, LOWER, UPPER, CAST, CONCAT, LEVENSHTEIN, CROW and all properties of Math as functions. You can also create your own functions.
Without AS
functions will always add a column identical to the function name to the result set containing the answer:
nSQL("users").query("select",["COUNT(*)"]).exec().then((rows) => {
console.log(rows) // <= [{"COUNT(*)":200}]
});
Temporary Tables
You can also select from an array of records:
nSQL().query("select").from([
{id: 1, name: "bill"},
{id: 2, name: "jeb"},
{id: 3, name: "val"}
]).where(["name", "=", "jeb"].exec()
Or even select from a rows returned in a promise. A good use case for this might be grabbing a json using fetch
and filtering the rows you get back.
nSQL().query("select").from({
table: () => {
return new Promise((res, rej) => {
res({
rows: [{id: 1, name: "bill"}, {id: 2, name: "jeb"}],
cache: true
});
});
}
as: "posts" // optional, used for joins and graph queries
}).where(["name", "=", "jeb"].exec()
The promise feature lets you infinitely nest nanoSQL queries:
nSQL().query("select").from({
table: () => nSQL("users").query("select").where(["age", ">", 23]).exec().then(r => {rows: r, cache: true});
}).where(["name", "=", "jeb"].exec()
Streaming Queries
In many cases javascript databases will load the entire query result into memory, then pass the whole object/array of rows to you as the result. This isn't always desirable, especially if you're scanning a very large number of records.
NanoSQL can optionally stream the query to you instead of loading results in memory.
To stream the results, simply replace .exec()
with .stream()
and follow the API provided below:
nSQL("users").query("select").stream((row) => {
// row received from stream
}, () => {
// query complete
}, () => {
// query error
})
While any query will work with .stream()
, there are some cases where the results MUST be loaded into memory to get the desired result, so using the .stream()
api in these cases will have no memory benefit over using .exec()
.
These query conditions will force query results into memory regardless of .stream()
:
- Using an aggregate function like
COUNT
. - Using
.groupBy
. - Using
.orderBy
on a column that doesn't have a secondary index or isn't the primary key. - Using
.orderBy
with more than one column.
If you use .stream()
in the above cases, you'll get all the query results at once after the query has finished, instead of incrementally as each row is selected.
The .stream()
api can also be used in delete
and upsert
queries, with identical benefits.
Query Cache
The query cache allows you to perform a query once, then paginate through the results of the query on demand. This is mostly useful for expensive or large queries that the end user is expected to be able to view multiple pages of results.
A few important restrictions to keep in mind about the cache. First the cache will not be updated with row data, so the cache represents the state of all the rows it scanned when they were scanned. Second the cache will remain in memory until it is removed.
To use the cache just replace .exec()
with .cache()
following the API described below. There are three methods of using the cache:
// 1. Return cache when query completes
nSQL("users").query("select").cache((cacheID, count) => {
// cacheID contains a UUID of this cache query
// count contains the total number of records in the cache
}, () => {
// query error
});
// 2. Return query pages as they are found
// this works similar to ".stream()", except as pages
// doesn't produce cache ID, doesn't require you to flush cache afterwards
nSQL("users").query("select").cache(() => {
// query complete
}, () => {
// query error
}, {
pageSize: 20,
onPage: (pageNum, rows) => {
// pageNum is the page number starting with 0
// rows is the query result
},
doNotCache: true
});
// 3. Return query pages AND cache result
nSQL("users").query("select").cache((cacheID, count) => {
// query complete
// cacheID contains a UUID of this cache query
// count contains the total number of records in the cache
},, () => {
// query error
}, {
pageSize: 20,
onPage: (pageNum, rows) => {
// pageNum is the page number starting with 0
// rows is the query result
}
});
Once you have the cacheID
from the cache query you can grab sections of the cache like this:
const rows = nSQL().getCache(cacheID, {offset: 20, limit: 20});
Clearing the cache is also very straightforward:
nSQL().clearCache(cacheID);
Observer Queries
Another option for exporting query results is with a listener. The listener acts similar to an observable, once you subscribe to the query you can be notified when the rows in the query where affected and also get a copy of the new results.
The api is simple, instead of .exec()
call .listen()
and use one of the two options for exporting the stream:
const observer = nSLQ("users").query("select").where(["age", ">", 23]).listen({ // optional arguments
// optional: debounce/throttle so that query doesn't fire more often than this. Default is 500ms
debounce: 500,
// optional: check new queries to see if any changes have happened, don't fire callbacks if no changes
unique: false,
// optional: if unique is true, an expensive deep comparison is performed on the rows, use this
// callback to replace that comparison with something faster if possible
compareFn: (rowsA, rowsB) => {
return rowsA.length !== rowsB.length
}
});
// choose one:
// 1. exec returns all rows in a single callback
observer.exec((rows, error) => {
// this function will be called on every change
// error will be undefined unless there was a problem
})
// 2. stream will send the rows one by one on each query
// stream cannot be used if unique:true is set in arguments
observer.stream((row) => {
// called for every row
}, () => {
// all rows sent for this query
}, (err) => {
// query encountered error
})
// unsubscribe
observer.unsubscribe();
The listener will trigger for the primary table in the query as well as any tables involved in a join and any tables involved in a graph query, even if the tables are in deeply nested graph queries.
The only exception is if you use array based or promise based tables in the join/graph queries, if that's the case you can manually trigger the observer to check for new results at any time by calling observer.trigger()
.
Selecting Rows Conditionally
You can request specific rows from the database based on a set of conditions. Let's look at some examples.
// Only get users over 25 years old.
nSQL("users").query("select").where(["age",">",25]).exec().then...
// Users over 25 and under 50
nSQL("users").query("select").where([["age",">",25],"AND",["age","<=",50]]).exec()
// Use a function
nSQL("users").query("select").where(user => user.age > 25).exec().then...
If you're passing in a function to the where statement, it acts exactly like the array filter statement, where each row is checked with the function and when it returns a truthy or truth value the row will be provided in the query result.
Otherwise supported comparative queries are <
, =
, !=
, >
, <=
, >=
, IN
, NOT IN
, REGEX
, LIKE
, , NOT LIKE
, BETWEEN
, NOT BETWEEN
, INCLUDES
, NOT INCLUDES
, INTERSECT
, INTERSECT ALL
and NOT INTERSECT
.
IN
and NOT IN
take an array and check to see if the value is in the array.
// get rows where the name is either jeb or scott.
nSQL("users").query("select").where(["name","IN",["jeb","scott"]]).exec();
BETWEEN
and NOT BETWEEN
take an array with two values to compare between:
// get rows where the age is between 19 and 32.
nSQL("users").query("select").where(["age","BETWEEN",[19,32]).exec();
INCLUDES
and NOT INCLUDES
check for a specific value inside the array of a column
// get all rows where the postIDs column is an array containing the number 3.
nSQL("users").query("select").where(["postIDs", "INCLUDES", 3]).exec();
// get all rows where the postIDs column is an array NOT containing the number 3.
nSQL("users").query("select").where(["postIDs", "NOT INCLUDES", 3]).exec();
INTERSECT ALL
, INTERSECT
and NOT INTERSECT
are useful to see if any values of a given array intersect with the values of an array column.
// get all rows where the postIDs column is an array containing 1 OR 2.
nSQL("users").query("select").where(["postIDs", "INTERSECT", [1, 2]]).exec();
// get all rows where the postIDs column is an array NOT containing 1 OR 2.
nSQL("users").query("select").where(["postIDs", "NOT INTERSECT", [1, 2]]).exec();
// get all rows where the postIDs column is an array containing 1 AND 2.
nSQL("users").query("select").where(["postIDs", "INTERSECT ALL", [1, 2]]).exec();
You can add as many conditions as you'd like to a where statement, separating each condition with AND
or OR
.
// Get all users who are over 20 years old and have blue as their favorite color.
nSQL("users").query("select").where([["age", ">", 20], "AND", ["favoriteColor", "=", "blue"]]).exec();
If you have more than two where
conditions it's good to nest them, like this:
nSQL("table").query("select").where([
["postYear", ">", 1999], "AND" [
["title", "LIKE", "searchTerm"], "OR", ["author", "LIKE", "searchTerm"]
]
]).exec()...
A recursive function is used to handle the nesting, so you can nest as many times as you need to.
You can also use functions inside the where
conditions:
// get all rows with levenshtien distance of less than 3 with "jeb", compare against the name column.
nSQL("users").query("select").where(["LEVENSHTEIN('jeb', name)", "<", 3]).exec()...
And it's also possible to query against nested values in each row:
nSQL("users").query("select").where(["props.nested.value", "=", "something"]).exec()...
Nested values can also be used in query functions:
nSQL("users").query("select").where(["LEVENSHTEIN('jeb', props.nested.name)", "<", 3]).exec()...
Finally, keep in mind if you use the AS
syntax in your rows, the where statement must use the original row names.
nSQL("users").query("select",["age AS howOld"]).where(["age",">",25]).exec()...
There are considerable performance considerations when setting up your queries, the performance docs are a good read.
Distinct
The distinct()
query argument allows you to select rows based on the unique value of specified columns.
// get rows with distinct city column
nSQL("users").query("select").distinct(["city"]).exec();
You can add as many columns as you'd like to the distinct query simply by making the array argument larger.
Order By
OrderBy
accepts one required argument, it's an object describing the rows you want sorted, and in what direction. Let's take a look.
// Sort by age descending, then name ascending.
nSQL("users").query("select").orderBy(["age DESC", "name ASC"]).exec();
You can sort by 1 or more columns, with the first columns in the object being sorted first, then the second, etc.
The sorting stacks as you add columns, for the example above everyone with the same age will be ordered together, then records with the same age will be sorted by their name. If we added a third column to the orderBy argument above, all records with the same name and age would be sorted by the value provided.
AS
statements get applied before OrderBy, so make sure you use the column alias for sorting.
nSQL("users").query("select",["username AS name"]).orderBy(["name ASC").exec();
You can also use query functions in the order by query:
nSQL("users").query("select").orderBy(["UPPER(name) ASC"]).exec();
Limit & Offset
Mostly used for pagination, these are very easy to use.
// Get 20 records at a time, 40 records below the first one.
nSQL("users").query("select").limit(20).offset(40).exec();
Copy To
Can be used to stream the results of the query into another table. This modifier works for any query type and will export each row of the result into the table provided. You can optionally pass in a second argument to mutate the selected rows before inserting them.
// copy results of upsert
nSQL("posts").query("upsert", {...}).copyTo("postsLog").exec();
// get a section of rows from one table into another
nSQL("users").query("select")
.where(["status", "=", "banned"])
.copyTo("bannedUsers").exec();
// stream analytics
nSQL("orders").query("select", ["COUNT(*) AS totalOrders", "AVG(total) AS avgOrder"])
.where(["orderDate", ">", Date.now() - (24 * 60 * 60 * 1000)])
.copyTo("orderStats").exec();
Advanced Select
Join
The join command takes an object or array of objects as it's argument, described by the InanoSQLJoinArgs Interface
Let's look at some examples
nSQL("users").query("select")
.join({
type: "left",
with: {table: "orders"},
on: ["users.id","=","orders.userID"]
}).exec();
When using join
you must use table.column syntax through out the rest of the query, like this:
nSQL("users").query("select", ["users.id", "users.name", "orders.date","orders.total"])
.join({
type: "left",
with: {table: "orders"},
on: ["users.id","=","orders.userID"]
})
.where(["orders.total",">",200])
.orderBy(["orders.date ASC"])
.exec().then..
Multiple joins are possible, just use an array in the .join()
method and pass in as many joins as you'd like.
Keep in mind join queries will use indexes where possible, so if you can reasonably use on
conditions that check against primary key or secondary index values you'll see improved performance.
Graph
The graph command takes an object or array of objects as it's argument, described by the InanoSQLGraphArgs Interface.
Let's look at some examples.
nSQL("users").query("select")
.graph({
key: "userOrders",
with: {table: "orders"},
on: ["users.id","=","orders.userID"]
}).exec();
You can also use query modifiers to adjust the graph result set the same as you would any other nanoSQL query.
nSQL("users").query("select")
.graph({
key: "userOrders",
with: {table: "orders"},
on: ["users.id","=","orders.userID"],
limit: 20,
orderBy: ["total ASC"],
groupBy: ["date ASC"],
select: ["id", "AVG(total) AS averageTotal", "date"],
graph: { // nested graph query
key: "items",
with: {table: "products"}
on: ["products.id", "IN", "orders.productList"]
}
}).exec();
It's also possible to have multiple graph queries simply by passing an array of graph objects into the .graph()
method instead of just one object.
Keep in mind graph queries will use indexes where possible, so if you can reasonably use on
conditions that check against primary key or secondary index values you'll see improved performance.
Union
The union command allows you to combine and aggregate results from a set of queries. It accepts two arguments, the first is an array of functions that return a promise and the second is a boolean that tells the union to wether to remove duplicate rows. By default duplicate rows are removed, pass true
into the second argument to include all rows (including duplicate ones).
The union command can be used in combination with .distinct()
to make sure specific columns are unique among all the returned results.
Query modifiers like .orderBy
, .where
and select arguments are applied to the results of the union.
// union results from two json endpoints
nSQL().query("select").union([
() => fetch("https://jsonplaceholder.typicode.com/posts").then(d => d.json()),
() => fetch("https://jsonplaceholder.typicode.com/comments").then(d => d.json())
]).exec().then...
// union results from three nanoSQL queries, distinct on id.
nSQL().query("select").union([
() => nSQL("users").query("select").exec(),
() => nSQL("posts").query("select").exec(),
() => nSQL("order").query("select").exec()
]).distinct(["id"]).exec().then...
Group By
GroupBy
is used to combine rows with the same value into a single row, almost exclusively used with aggregate functions. It takes exactly the same arguments as orderBy
.
If no aggregate functions are used in the query, groupBy
has the same effect as orderBy
.
Lets look at some examples:
// Let's get the average salary of every department
nSQL("employees")
.query("select",["department","AVG(salary) AS averageSalary"])
.groupBy(["department ASC"])
.exec()..
// Or the average transaction cost for each day
nSQL("orders")
.query("select",["date","AVG(total) AS averageTotal"])
.groupBy(["date ASC"])
.exec()...
// Total number of transactions each day
nSQL("orders")
.query("select",["date","COUNT(*) AS numberOfTransactions"])
.groupBy(["date ASC"])
.exec()...
You can also use functions in group By arguments:
nSQL("employees")
.query("select",["department","AVG(salary) AS averageSalary"])
.groupBy(["TRIM(department) ASC"])
.exec()..
Having
Having
follows exactly the same syntax as where
, except it runs AFTER groupBy
and join
, allowing you to select based on results of a join and/or group by command. You typically won't use having
unless you also have a groupBy
or join
command already in place, although this isn't a requirement.
First take a look at the where
syntax here.
Here is a use case for having
:
nSQL("users")
.query("select",["eyeColor", "AVG(age) AS averageAge"])
.groupBy(["eyeColor ASC"])
.having(["averageAge",">",20])
.exec()...
As / Alias
NanoSQL follows MySQL in the order of the select
statement queries. Select arguments are applied in this order: 1. Where
2. Join
3. Group By
4. AS
statements and functions applied. 5. Having
6. OrderBy
7. Offset
& Limit
This means that when you use .where()
, .join()
, and .groupBy()
you'll have to use the original column names and not the alias column name you provided.
For example:
nSQL("users")
.query("select",["orders.userID AS ID", "users.name AS Customer", "COUNT(*) AS Orders", "SUM(orders.total) AS Total"])
.where([["users.balance", ">", 100], "OR",["users.age", ">", 45]])
.join({
type:"left",
with: {table: "orders"},
on: ["orders.userID","=","users.id"]
})
.groupBy(["orders.userID ASC"])
// AS statements parsed here.
.having(["Total", ">", 100])
.orderBy(["Total DESC"])
.exec().then((rows) => {...})
And something without a join to make it simple:
nSQL("users")
.query("select",["username AS name", "age AS howOld"])
.where(["age",">",20])
.groupBy(["age ASC"])
// AS statements parsed here.
.having(["howOld",">",20]) // This is technically redundant.
.orderBy(["name ASC"])
.exec().then...
With (Graph/Join Syntax)
The WITH syntax is used with Graph and Join queries. Using with
you can join/graph temporary tables and internal tables with relative ease, or any combination of internal tables and temporary tables.
All examples are using graph
queries but the syntax is identical for the with
property in join queries.
Using an internal table:
nSQL("users").query("select").graph([
{
key: "posts",
with: {table: "posts"},
on: ["posts.userId", "=", "users.id"]
}
]).exec()
Using an internal table with an alias:
nSQL("users").query("select").graph([
{
key: "posts",
with: {
table: "posts"
as: "blogPosts"
},
on: ["blogPosts.userId", "=", "users.id"]
}
]).exec()
Using a static array table (must use alias):
nSQL("users").query("select").graph([
{
key: "posts",
with: {
table: [
{title: "hello", userId: 1},
{title: "world", userId: 2}
]
as: "posts"
},
on: ["posts.userId", "=", "users.id"]
}
]).exec()
Using a promise returned table (must use alias)
nSQL("users").query("select").graph([
{
key: "posts",
with: {
table: () => fetch("https://jsonplaceholder.typicode.com/posts").then(d => d.json()).then(j => {
// if you're returning a whole table, always pass "cache: true"
return {rows: j, cache: true};
})
as: "posts"
},
on: ["posts.userId", "=", "users.id"]
}
]).exec()
Using a promise to return filtered rows (muse use alias)
nSQL("users").query("select").graph([
{
key: "posts",
with: {
table: (where) => {
// "where" argument contains a converted where statement
// derived from the "on" property
// for this example the `where` would be something like
// ["userId", "=", 2]
return new Promise((res, rej) {
return fetch(`http://example.com/posts?getByUserId=${where[2]}`).then(d => d.json()).then(d => {
return {
rows: d,
filtered: true // pass filtered if only the results of `where` were returned
}
});
});
}
as: "posts"
},
on: ["posts.userId", "=", "users.id"]
}
]).exec()
Aggregate Functions
Aggregate functions take a collection of rows and combine them into a single row with a resulting value.
Aggregate functions can be used in combination with groupBy
to get multiple aggregate values at once. The groupBy
arguments are used to determine what rows are merged together for the aggregate function. Reading the groupBy docs will help familiarize yourself with how aggregate functions work with groupBy
.
COUNT
Count is used to get the number of records that match the argument. If the argument is "*" every record is counted, if a column value is provided instead all rows that have a truthy value in that column are counted.
Syntax
COUNT(expression)
Parameter Values
Parameters | Description |
---|---|
expression | "*" to count every record or column to check for truthy value. |
Examples
// Get the total number of users in the database
nSQL("users").query("select", ["COUNT(*)"]).exec();
// Get the number of users with a balance
nSQL("users").query("select", ["COUNT(balance)"]).exec();
// Get the number of users for each account type
nSQL("users").query("select", ["type", "COUNT(*)"]).groupBy(["type ASC"]).exec();
MAX & MIN
Min & Max functions are used to get the highest or lowest value in a given column on a table.
Syntax
MAX(expression)
MIN(expression)
Parameter Values
Parameters | Description |
---|---|
expression | Column to compare values. |
Examples
// Get the oldest user
nSQL("users").query("select", ["name", "MAX(age)"]).exec();
// Get the youngest user
nSQL("users").query("select", ["name", "MIN(age)"]).exec();
// Get the oldest user for each account type
nSQL("users").query("select", ["type", "MAX(age)"]).groupBy(["type ASC"]).exec();
AVG
Avg function is used to average all the values on a given column together.
Syntax
AVG(expression)
Parameter Values
Parameters | Description |
---|---|
expression | Column to average values. |
Examples
// Get the average age of all users
nSQL("users").query("select", ["AVG(age)"]).exec();
// Get the average age for each account type
nSQL("users").query("select", ["type", "AVG(age)"]).groupBy(["type ASC"]).exec();
SUM
Sum function is used to add all the values on a given column together.
Syntax
SUM(expression)
Parameter Values
Parameters | Description |
---|---|
expression | Column to add values. |
Examples
// Get the combined age of all users
nSQL("users").query("select", ["SUM(age)"]).exec();
// Get the combined age for each account type
nSQL("users").query("select", ["type", "SUM(age)"]).groupBy(["type ASC"]).exec();
Simple Functions
Simple functions normally transform the value in a specific column to a desired value. Unlike aggregate functions, simple functions will return a value for every single row that is queried.
GREATEST & LEAST
Greatest and least functions are used to get the highest or lowest value inside the same row, can also be used to compare each row's value against a provided value.
Another way to think of Greatest & Least is it's like Min & Max but only compares a single row's values to each other instead of comparing all rows on a table.
Syntax
GREATEST(arg1, arg2, arg3, ....)
LEAST(arg1, arg2, arg3, ....)
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, .... | Columns to compare values. |
Examples
// returns 20 or the users age if it's higher
nSQL("users").query("select", ["name", "GREATEST(20, age)"]).exec();
// can also be used to compare one row value to another
nSQL("users").query("select", ["name", "GREATEST(balance, points)"]).exec();
LOWER & UPPER
These functions take a row column and either uppercase or lowercase the provided column.
Syntax
UPPER(expression)
LOWER(expression)
Parameter Values
Parameters | Description |
---|---|
expression | Column to mutate. |
Examples
// returns uppercase of every users's name
nSQL("users").query("select", ["UPPER(name)"]).exec();
// can also be used to make case insensative sorting.
nSQL("users").query("select", ["name"]).orderBy(["UPPER(name) ASC"]).exec();
FORMAT_NUMBER
This function takes a number and converts it to a formated string, optionally fixing the string to a specific length.
If no second argument is passed, the number will be truncated to 2 decimal places.
Syntax
FORMAT_NUMBER(expression, truncate)
Parameter Values
Parameters | Description |
---|---|
expression | Column or number to mutate. |
truncate | The number of decimal places to truncate to. |
Examples
// returns uppercase of every users's name
nSQL("users").query("select", ["FORMAT_NUMBER(balance)"]).exec();
// result: 10,00,203.38
TRIM
This function takes a row column and removes trailing and leading whitespace.
Syntax
TRIM(expression)
Parameter Values
Parameters | Description |
---|---|
expression | Column to mutate. |
Examples
// returns names without leading or trailing whitespace
nSQL("users").query("select", ["TRIM(name)"]).exec();
IF
Evaluates an expression, if the expression is true the second argument is returned, otherwise the third argument is returned.
Syntax
IF(expression, trueArg, falseArg)
Parameter Values
Parameters | Description |
---|---|
expression | Expression to evaluate. |
trueArg | Return this value if the expression is true. |
falseArg | Return this value if the expression is false. |
Examples
// returns 'name is bill' if the name is bill, otherwise 'not bill'
nSQL("users").query("select", ["IF(name='bill', 'name is bill', 'not bill')"]).exec();
// returns "positive balance" if balance is greater than 0, otherwise "negative balance".
nSQL("users").query("select", ["IF(balance>0, 'positive balance', 'negative balance')"]).exec();
CAST
This function takes a column value and type, then mutates the column value to the provided type.
Syntax
CAST(column, type)
Parameter Values
Parameters | Description |
---|---|
column | Column to mutate. |
type | nanoSQL type to mutate the column into. |
Examples
// return body of comments converted to html special characters.
nSQL("comments").query("select", ["CAST(body, 'safestr')"]).exec();
CONCAT
Works the same as String.join() in javascript, merges multiple values into a single string.
Syntax
CONCAT(arg1, arg2, arg3, ....)
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, .... | Columns to concatenate, can also pass in raw strings. |
Examples
// Get users whole name
nSQL("users").query("select", ["CONCAT(firstName, ' ', lastName) AS name"]).exec()
CONCAT_WS
Works the same as String.join() in javascript, merges multiple values into a single string. Unlike CONCAT
, you can pass in a custom value that is used to join the strings together.
Syntax
CONCAT_WS(expression, arg1, arg2, arg3, ....)
Parameter Values
Parameters | Description |
---|---|
expression | Value to put between each string |
arg1, arg2, arg3, .... | Columns to concatenate, can also pass in raw strings. |
Examples
// Get users whole name
nSQL("users").query("select", ["CONCAT_WS(' ', firstName, lastName) AS name"]).exec()
REPLACE
Searches a provided string for a provided value and replaces it with a new value.
Syntax
REPLACE(subject, find, replace)
Parameter Values
Parameters | Description |
---|---|
subject | String or column to search. |
find | String to find in subject |
replace | String to replace when find value is in subject. |
Examples
// find all users names bill and return their name as william.
nSQL("users").query("select", ["REPLACE(name, 'bill', 'william')"]).exec():
STRCMP
Compares two strings together; returns 0 if strings match, -1 if first string is greater than second string and1 otherwise.
Syntax
STRCMP(subject1, subject2)
Parameter Values
Parameters | Description |
---|---|
subject1 | String or column to use for comparison. |
subject2 | String or column to use for comparison. |
Examples
// sort all user's name against 'bill'.
nSQL("users").query("select").orderBy(["STRCMP(name, 'bill') ASC"]).exec():
CROW
Get the distance between rows and a given GPS coordinate using the Haversine formula.
Default distance is in km, update the nSQL().planetRadius
value to get results in another size.
Syntax
CROW(column, latitude, longitude)
Parameter Values
Parameters | Description |
---|---|
column | Row column to get GPS points. Column must be an object with lat and lon properties. |
latitude | Latitude of center point. |
longitude | Longitude of center point. |
Examples
// sort rows by distance from point
nSQL("users").query("select").orderBy(["CROW(address, 16.83268871, -75.94151676) DESC"]).exec();
// get rows within radius of point
nSQL("users").query("select").where(["CROW(address, 16.83268871, -75.94151676)", "<", 4]).exec();
LEVENSHTEIN
Finds the edit distance between two strings.
Syntax
LEVENSHTEIN(expression1, expression2)
Parameter Values
Parameters | Description |
---|---|
expression1 | First word or column to use Levenshtein formula. |
expression2 | Second word or column to use in Levenshtein formula. |
Examples
// Get the edit distance against "jeb" for all users names
nSQL("users").query("select", ["LEVENSHTEIN('jeb', firstName)"]).exec()
// Get all users who's name is within an edit distance of 3 of "jeb"
nSQL("users").query("select").where(["LEVENSHTEIN('jeb', firstName)", "<", 3]).exec()
ADD
Add multiple values/columns together
Syntax
ADD(arg1, arg2, arg3, ...)
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, ... | Columns or numbers to add together |
Examples
// Get the age + 30 of all users
nSQL("users").query("select", ["ADD(age, 30)"]).exec()
// Add age, 30 and balance
nSQL("users").query("select", ["ADD(age, 30, balance)"]).exec()
SUB
Subtract multiple values/columns together
Syntax
SUB(arg1, arg2, arg3, ...)
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, ... | Columns or numbers to add together |
Examples
// Get the age - 30 of all users
nSQL("users").query("select", ["SUB(age, 30)"]).exec()
// Subtract age, 30 and balance
nSQL("users").query("select", ["SUB(age, 30, balance)"]).exec()
DIV
Divide values and/or columns.
Syntax
DIV(arg1, arg2)
Parameter Values
Parameters | Description |
---|---|
arg1 | Column or number for the left or top of the division |
arg2 | Column or number for the right or bottom of the division |
Examples
// Devide all balances by 100: balance / 100
nSQL("users").query("select", ["DIV(balance, 100)"]).exec()
MULT
Multiply values or columns together
Syntax
MULT(arg1, arg2, arg3, ...)
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, ... | Columns or numbers to add together |
Examples
// Multiply all user's age by 30
nSQL("users").query("select", ["MULT(age, 30)"]).exec()
// Multiply age, 30 and balance
nSQL("users").query("select", ["MULT(age, 30, balance)"]).exec()
MOD
Get the modulus of two numbers.
Syntax
MOD(arg1, arg2)
Parameter Values
Parameters | Description |
---|---|
arg1 | The larger number to get the remainder from |
arg2 | The remainder/devide value |
Examples
// Get the modulus of 30 and the user's age.
nSQL("users").query("select", ["MOD(30, age)"]).exec()
// Get the modulus of the user's balance and 20.
nSQL("users").query("select", ["MOD(balance, 20)"]).exec()
TRUNCATE
Get a number reduced to the provided number of decimals
Syntax
TRUNCATE(arg1, arg2)
Parameter Values
Parameters | Description |
---|---|
arg1 | The number to truncate. |
arg2 | The number of decimal places to truncate to. |
Examples
// Get the balance truncated to 0 decimal places
nSQL("users").query("select", ["TRUNCATE(balance, 0)"]).exec()
Math
All javascript Math functions that are a property of the global Math
object are supported:
Supported By IE9+: (These math functions are safe in almost any environment)
ABS, ACOS, ASIN, ATAN, ATAN2, CEIL, COS, EXP, FLOOR, LOG, MAX, MIN, POW, RANDOM, ROUND, SIN, SQRT, TAN
Supported By ES6: (These functions require a newer environment)
ACOSH, ASINH, ATANH, CBRT, EXPM1, CLZ32, COSH, FROUND, HYPOT, IMUL, LOG1P, LOG2, LOG10, SIGN, SINH, TANH, TRUNC, E, LN10, LN2, LOG10E, LOG2E, PI, SQRT1_2, SQRT2
Internally nanoSQL uses Object.getOwnPropertyNames(Math) to generate all the math functions, which means the javascript environment must support the math function you're attempting to use, which might not always be the case. If you're using a more obscure or new ES6 math function it might be a good idea to implement it as a custom function.
The Mozilla Docs on the Math function are a good place to see how the math functions are used.
Syntax
ABS(arg1, arg2, arg3, ....)
SQRT(arg1, arg2, arg3, ....)
ASIN(arg1, arg2, arg3, ....)
...
Parameter Values
Parameters | Description |
---|---|
arg1, arg2, arg3, .... | Arguments to pass to math function. Can be raw number or column. |
Examples
// Get absolute value of every balance
nSQL("users").query("select", ["ABS(balance)"]).exec()
// Get square value of users age
nSQL("users").query("select", ["POW(age, 2)"].exec();