Fluree supports JSON-LD based analytical queries. This document provides comprehensive syntax reference based on the Malli schema definitions and examples from the codebase.
Fluree queries support multiple naming conventions that are automatically normalized:
- camelCase (preferred):
selectOne,orderBy,groupBy - kebab-case:
select-one,order-by,group-by - Clojure Keywords:
:select,:selectOne,:select-one
All examples in this document use camelCase format as the preferred style.
{
"@context": <context-definition>,
"select": <select-clause>,
"where": <where-clause>,
"from": <from-clause>,
"fromNamed": <from-named-clause>,
"orderBy": <order-by-clause>,
"groupBy": <group-by-clause>,
"having": <having-clause>,
"values": <values-clause>,
"limit": <limit-clause>,
"offset": <offset-clause>,
"t": <time-clause>,
"opts": <options-map>
}Required: One select clause (select, selectOne, selectDistinct, or
construct)
Optional: All other clauses
Defines namespace prefixes for IRIs in the query.
"@context": {
"prefix": "iri",
...
}{
"@context": {
"schema": "http://schema.org/",
"ex": "http://example.org/",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
}
}{
"@context": [
{"schema": "http://schema.org/"},
{"ex": "http://example.org/"}
]
}Specifies what data to return from the query.
"select": ["?var1", "?var2"]"select": "*""select": [
"?name",
{"?avgAge": ["avg", "?age"]},
{"?count": ["count", "?person"]}
]"selectOne": ["?name", "?age"]"selectDistinct": ["?type"]"select": {
"?person": [
"schema:name",
"schema:age",
{
"schema:knows": [
"schema:name"
]
}
]
}Defines patterns to match in the data.
"where": {
"@id": "?person",
"@type": "schema:Person",
"schema:name": "?name",
"schema:age": "?age"
}"where": [
{"@id": "?person", "@type": "schema:Person"},
{"@id": "?person", "schema:name": "?name"},
{"@id": "?person", "schema:age": "?age"}
]"where": {
"@id": "?person",
"schema:knows/schema:name": "?friendName"
}"where": {
"@id": "?person",
"schema:address": {
"@id": "?address",
"schema:city": "?city",
"schema:postalCode": "?zip"
}
}"where": [
{"@id": "?person", "schema:name": "?name"},
{"optional": [
{"@id": "?person", "schema:age": "?age"}
]}
]"where": [
{"@id": "?person", "schema:name": "?name"},
{"union": [
[{"@id": "?person", "schema:email": "?contact"}],
[{"@id": "?person", "schema:phone": "?contact"}]
]}
]"where": [
{"@id": "?person", "schema:age": "?age"},
{"filter": [">", "?age", 18]}
]"where": [
{"@id": "?person", "schema:age": "?age"},
{"bind": [
["?isAdult", [">=", "?age", 18]]
]}
]"where": [
{"@id": "?person", "schema:name": "?name"},
{"exists": [
{"@id": "?person", "schema:age": "?age"}
]}
]"where": [
{"@id": "?person", "schema:name": "?name"},
{"not-exists": [
{"@id": "?person", "schema:age": "?age"}
]}
]"where": [
{"@id": "?person", "schema:name": "?name"},
{"minus": [
{"@id": "?person", "schema:age": "?age"}
]}
]"where": [
{"@id": "?person", "schema:name": "?name"},
{"values": [
["?name", ["Alice", "Bob", "Charlie"]]
]}
]"="- Equal"!="- Not equal"<"- Less than">"- Greater than"<="- Less than or equal">="- Greater than or equal
"&&"- Logical AND"||"- Logical OR"!"- Logical NOT
"+"- Addition"-"- Subtraction"*"- Multiplication"/"- Division
"str"- Convert to string"strlen"- String length"substr"- Substring"strStarts"- String starts with"strEnds"- String ends with"contains"- String contains"regex"- Regular expression match
"bound"- Check if variable is bound"isIRI"- Check if value is IRI"isBlank"- Check if value is blank node"isLiteral"- Check if value is literal
"count"- Count values"count-distinct"- Count distinct values"sum"- Sum numeric values"avg"- Average of numeric values"min"- Minimum value"max"- Maximum value"sample1"- Sample one value"groupconcat"- Concatenate values
["function-name", "arg1", "arg2", ...]{"filter": [">", "?age", 18]}
{"filter": ["&&", [">", "?age", 18], ["<", "?age", 65]]}
{"filter": ["regex", "?name", "^John"]}
{"bind": [["?adult", [">=", "?age", 18]]]}Sorts query results.
"orderBy": "?name""orderBy": ["?name", "?age"]"orderBy": [["desc", "?age"]]"orderBy": [["desc", "?age"], ["asc", "?name"]]Groups results by specified variables.
"groupBy": "?department""groupBy": ["?department", "?location"]{
"select": ["?department", {"?avgAge": ["avg", "?age"]}],
"where": {
"@id": "?person",
"schema:department": "?department",
"schema:age": "?age"
},
"groupBy": "?department"
}Filters grouped results based on aggregate conditions.
"having": ["function", "arg1", "arg2"]{
"select": ["?name", "?favNums"],
"where": {
"schema:name": "?name",
"ex:favNums": "?favNums"
},
"groupBy": "?name",
"having": [">=", ["count", "?favNums"], 2]
}{
"select": ["?department", {"?count": ["count", "?person"]}],
"where": {
"@id": "?person",
"schema:department": "?department"
},
"groupBy": "?department",
"having": [">", ["count", "?person"], 5]
}Provides explicit values for variables.
"values": [
["?var1", [value1, value2, ...]],
["?var2", [value1, value2, ...]]
]{
"select": ["?name", "?age"],
"where": {
"@id": "?person",
"schema:name": "?name",
"schema:age": "?age"
},
"values": [
["?name", ["Alice", "Bob", "Charlie"]]
]
}Controls result set size and pagination.
"limit": 10,
"offset": 20{
"select": ["?name", "?age"],
"where": {
"@id": "?person",
"schema:name": "?name",
"schema:age": "?age"
},
"orderBy": "?name",
"limit": 10,
"offset": 0
}Queries data at specific points in time.
"t": <time-specification>"t": "2023-01-01T00:00:00.000Z""t": 1000Specifies named graphs to query.
"from": "graph-name"{
"select": ["?s", "?p", "?o"],
"from": "my-graph",
"where": {
"@id": "?s",
"?p": "?o"
}
}Query execution options.
"opts": {
"max-fuel": 1000000,
"identity": "did:example:123",
"format": "fql",
"meta": true
}max-fuel- Maximum computational resourcesidentity- Identity for policy evaluationformat- Output format (:fqlor:sparql)meta- Include metadata in resultspolicy- Policy restrictionspolicy-class- Policy class restrictionspolicy-values- Values passed to policy queriesdefault-allow- Iftrue, allow access when no policies apply (default:falsewhich means deny)objectVarParsing- Controls whether bare object strings that look like variables (e.g.,"?x") are parsed as variables in the WHERE clause.- Default:
true - When
false, scalar object values like"?not-a-var"are treated as string literals. Use the explicit JSON-LD form to bind a variable:{"@variable": "?v"}. - This flag does not affect variable parsing for
@idor predicate keys; those are always treated as variables when they begin with?. - Explicit
{"@variable": "?..."}is always honored regardless of this flag.
- Default:
{
"@context": {"ex": "http://example.org/"},
"opts": {"objectVarParsing": false},
"select": ["?s"],
"where": [
{"@id": "?s", "ex:prop": "?not-a-var"}
]
}To bind a variable when the flag is false:
{
"@context": {"ex": "http://example.org/"},
"opts": {"objectVarParsing": false},
"select": ["?v"],
"where": [
{"@id": "ex:s", "ex:prop": {"@variable": "?v"}}
]
}{
"@context": {
"schema": "http://schema.org/",
"ex": "http://example.org/"
},
"select": ["?name", "?age"],
"where": {
"@id": "?person",
"@type": "schema:Person",
"schema:name": "?name",
"schema:age": "?age"
},
"orderBy": "?name"
}{
"@context": {
"schema": "http://schema.org/"
},
"select": [
"?department",
{"?avgAge": ["avg", "?age"]},
{"?count": ["count", "?person"]}
],
"where": {
"@id": "?person",
"schema:department": "?department",
"schema:age": "?age"
},
"groupBy": "?department",
"having": [">", ["count", "?person"], 5],
"orderBy": [["desc", "?avgAge"]]
}{
"@context": {
"schema": "http://schema.org/",
"ex": "http://example.org/"
},
"select": ["?person", "?name", "?friendName"],
"where": [
{
"@id": "?person",
"@type": "schema:Person",
"schema:name": "?name",
"schema:age": "?age"
},
{
"@id": "?person",
"schema:knows": "?friend"
},
{
"@id": "?friend",
"schema:name": "?friendName"
},
{
"filter": ["&&", [">", "?age", 18], ["<", "?age", 65]]
}
],
"orderBy": "?name",
"limit": 50
}Common query errors and their causes:
- Missing select clause: Query must have exactly one of
select,select- one,select-distinct, orconstruct - Invalid variable: Variables must start with
?(e.g.,?name) - Invalid function: Function calls must follow proper syntax:
["function- name", "arg1", "arg2"]
- Invalid literal: Check that strings, numbers, and booleans are properly formatted
- Invalid IRI: IRIs must be valid URIs or use defined prefixes
- Unbound variables: Variables in SELECT must be bound in WHERE clause
- Invalid aggregation: Aggregate functions can only be used with GROUP BY
- Use indexes: Structure queries to leverage existing property and type indexes
- Limit results: Always use LIMIT for large datasets
- Specific patterns: Use specific type constraints early in WHERE clause
- Avoid Cartesian products: Ensure proper joins between graph patterns
- Filter early: Apply filters as early as possible in the query execution