Quickstart: Query Data
This guide introduces you to querying data in Fluree using both JSON-LD Query and SPARQL.
Prerequisites
- Fluree server running with data (complete previous quickstarts)
- Sample data from Write Data guide
Query Languages
Fluree supports two query languages:
- JSON-LD Query: Fluree's native JSON-based query language
- SPARQL: W3C standard RDF query language
Both provide access to the same data and features.
JSON-LD Query
Basic SELECT Query
Retrieve all person names:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name"],
"where": [
{ "@id": "?person", "schema:name": "?name" }
]
}'
Response:
[
{ "name": "Alice" },
{ "name": "Bob" },
{ "name": "Carol" }
]
Query Multiple Properties
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name", "?email"],
"where": [
{ "@id": "?person", "schema:name": "?name" },
{ "@id": "?person", "schema:email": "?email" }
]
}'
Response:
[
{ "name": "Alice", "email": "alice@example.org" },
{ "name": "Bob", "email": "bob@example.org" },
{ "name": "Carol", "email": "carol@example.org" }
]
Filter Results
Query with a specific filter:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name", "?age"],
"where": [
{ "@id": "?person", "schema:name": "?name" },
{ "@id": "?person", "schema:age": "?age" }
],
"filter": "?age > 25"
}'
Query Specific Entity
Query a specific entity by IRI:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"ex": "http://example.org/ns/",
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name", "?email", "?age"],
"where": [
{ "@id": "ex:alice", "schema:name": "?name" },
{ "@id": "ex:alice", "schema:email": "?email" },
{ "@id": "ex:alice", "schema:age": "?age" }
]
}'
Query with Relationships
Follow links between entities:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?personName", "?companyName"],
"where": [
{ "@id": "?person", "schema:name": "?personName" },
{ "@id": "?person", "schema:worksFor": "?company" },
{ "@id": "?company", "schema:name": "?companyName" }
]
}'
Response:
[
{ "personName": "Alice", "companyName": "Acme Corp" }
]
SPARQL
Basic SELECT Query
The same queries in SPARQL syntax:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT ?name
FROM <mydb:main>
WHERE {
?person schema:name ?name .
}
'
Query Multiple Properties
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT ?name ?email
FROM <mydb:main>
WHERE {
?person schema:name ?name .
?person schema:email ?email .
}
'
Filter Results
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT ?name ?age
FROM <mydb:main>
WHERE {
?person schema:name ?name .
?person schema:age ?age .
FILTER (?age > 25)
}
'
Query with Relationships
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT ?personName ?companyName
FROM <mydb:main>
WHERE {
?person schema:name ?personName .
?person schema:worksFor ?company .
?company schema:name ?companyName .
}
'
Time Travel Queries
Query historical data using time specifiers.
Query at Specific Transaction
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main@t:1",
"select": ["?name"],
"where": [
{ "@id": "?person", "schema:name": "?name" }
]
}'
This shows data as it existed at transaction 1.
Query at ISO Timestamp
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main@iso:2024-01-22T10:00:00Z",
"select": ["?name"],
"where": [
{ "@id": "?person", "schema:name": "?name" }
]
}'
Query at Commit ContentId
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main@commit:bafybeig...",
"select": ["?name"],
"where": [
{ "@id": "?person", "schema:name": "?name" }
]
}'
See Time Travel for comprehensive details.
History Queries
Track changes to entities over time by specifying a time range in the from clause.
Entity History
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"ex": "http://example.org/ns/",
"schema": "http://schema.org/"
},
"from": "mydb:main@t:1",
"to": "mydb:main@t:latest",
"select": ["?name", "?age", "?t", "?op"],
"where": [
{ "@id": "ex:alice", "schema:name": { "@value": "?name", "@t": "?t", "@op": "?op" } },
{ "@id": "ex:alice", "schema:age": "?age" }
],
"orderBy": "?t"
}'
The @t annotation binds the transaction time, and @op binds the operation type as a boolean (true = assert, false = retract).
Response shows all changes:
[
["Alice", 30, 1, true],
["Alice", 30, 5, false],
["Alicia", 31, 5, true]
]
Property History
Track changes to a specific property:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"ex": "http://example.org/ns/",
"schema": "http://schema.org/"
},
"from": "mydb:main@t:1",
"to": "mydb:main@t:latest",
"select": ["?age", "?t", "?op"],
"where": [
{ "@id": "ex:alice", "schema:age": { "@value": "?age", "@t": "?t", "@op": "?op" } }
],
"orderBy": "?t"
}'
Response:
[
[30, 1, true],
[30, 5, false],
[31, 5, true]
]
Aggregations
Count Results
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT (COUNT(?person) AS ?count)
FROM <mydb:main>
WHERE {
?person schema:name ?name .
}
'
Average, Min, Max
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/sparql-query" \
-d '
PREFIX schema: <http://schema.org/>
SELECT (AVG(?age) AS ?avgAge) (MIN(?age) AS ?minAge) (MAX(?age) AS ?maxAge)
FROM <mydb:main>
WHERE {
?person schema:age ?age .
}
'
Limiting Results
JSON-LD Query Limit
{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name"],
"where": [
{ "@id": "?person", "schema:name": "?name" }
],
"limit": 10
}
SPARQL Limit and Offset
PREFIX schema: <http://schema.org/>
SELECT ?name
FROM <mydb:main>
WHERE {
?person schema:name ?name .
}
ORDER BY ?name
LIMIT 10
OFFSET 20
Ordering Results
JSON-LD Query Order
{
"@context": {
"schema": "http://schema.org/"
},
"from": "mydb:main",
"select": ["?name", "?age"],
"where": [
{ "@id": "?person", "schema:name": "?name" },
{ "@id": "?person", "schema:age": "?age" }
],
"orderBy": ["?age"]
}
SPARQL Order
PREFIX schema: <http://schema.org/>
SELECT ?name ?age
FROM <mydb:main>
WHERE {
?person schema:name ?name .
?person schema:age ?age .
}
ORDER BY DESC(?age)
Multi-Ledger Queries
Query across multiple ledgers:
curl -X POST http://localhost:8090/v1/fluree/query \
-H "Content-Type: application/json" \
-d '{
"@context": {
"schema": "http://schema.org/"
},
"from": ["customers:main", "orders:main"],
"select": ["?customerName", "?orderTotal"],
"where": [
{ "@id": "?customer", "schema:name": "?customerName" },
{ "@id": "?order", "schema:customer": "?customer" },
{ "@id": "?order", "schema:totalPrice": "?orderTotal" }
]
}'
See Datasets for comprehensive multi-graph query documentation.
Understanding Query Results
JSON-LD Query Results
Results are returned as an array of objects:
[
{ "name": "Alice", "age": 30 },
{ "name": "Bob", "age": 25 }
]
SPARQL Results
SPARQL returns results in SPARQL JSON format:
{
"head": {
"vars": ["name", "age"]
},
"results": {
"bindings": [
{
"name": { "type": "literal", "value": "Alice" },
"age": { "type": "literal", "value": "30", "datatype": "http://www.w3.org/2001/XMLSchema#integer" }
},
{
"name": { "type": "literal", "value": "Bob" },
"age": { "type": "literal", "value": "25", "datatype": "http://www.w3.org/2001/XMLSchema#integer" }
}
]
}
}
See Output Formats for format details.
Query Performance Tips
1. Use Specific Patterns
More specific patterns are faster:
Good:
{ "@id": "ex:alice", "schema:name": "?name" }
Less efficient:
{ "@id": "?person", "?predicate": "?value" }
2. Filter Early
Apply filters in WHERE clauses when possible:
"where": [
{ "@id": "?person", "schema:age": "?age" }
],
"filter": "?age > 25"
3. Limit Results
Always use LIMIT for large result sets:
"limit": 100
4. Use Indexes
Queries leverage automatic indexes. Structure queries to take advantage:
- Subject-based lookups are fast
- Predicate-based lookups are fast
- Complex graph patterns may be slower
See Explain Plans for query optimization.
Common Query Patterns
Find All Types
SELECT DISTINCT ?type
FROM <mydb:main>
WHERE {
?entity a ?type .
}
Find All Predicates
SELECT DISTINCT ?predicate
FROM <mydb:main>
WHERE {
?subject ?predicate ?object .
}
Inverse Relationships
Find what points to an entity:
SELECT ?source ?predicate
FROM <mydb:main>
WHERE {
?source ?predicate <http://example.org/ns/alice> .
}
Optional Properties
Query with optional values:
PREFIX schema: <http://schema.org/>
SELECT ?name ?email ?phone
FROM <mydb:main>
WHERE {
?person schema:name ?name .
?person schema:email ?email .
OPTIONAL { ?person schema:telephone ?phone }
}
Error Handling
Query Errors
Common query errors:
{
"error": "QueryError",
"message": "Ledger not found: mydb:main",
"code": "LEDGER_NOT_FOUND"
}
{
"error": "ParseError",
"message": "Invalid JSON-LD: unexpected token",
"code": "PARSE_ERROR"
}
Empty Results
Empty result set (not an error):
[]
Next Steps
Now that you can query data:
- Learn Advanced Queries: Explore JSON-LD Query and SPARQL documentation
- Understand Time Travel: Deep dive into Time Travel
- Optimize Queries: Read about Explain Plans
- Multi-Graph Queries: Learn about Datasets
Related Documentation
- JSON-LD Query - Complete JSON-LD query reference
- SPARQL - Complete SPARQL reference
- Output Formats - Result format options
- Time Travel - Historical queries
- Graph Crawl - Graph traversal