IntelliJ IDEA or Eclipse.
The SurrealDB Java SDK is available on the Maven Central repository. You can install it using Gradle or Maven. Copy the relevant code snippet into your build.gradle
or pom.xml
file to add the SDK as a dependency.
The latest version of the SDK is currently 0.2.0
ext { surrealdbVersion = "0.2.0" } dependencies { implementation "com.surrealdb:surrealdb:${surrealdbVersion}" }
val surrealdbVersion by extra("0.2.0") dependencies { implementation("com.surrealdb:surrealdb:${surrealdbVersion}") }
<dependency> <groupId>com.surrealdb</groupId> <artifactId>surrealdb</artifactId> <version>0.2.0</version> </dependency>
The first step towards sending queries is instantiating the driver. In the following example we use a try-with-resources block to ensure the driver is properly closed after use. After instantiating the driver, we will connect to an in-memory database, and select our namespace and database.
SurrealDB.javapackage me.yourname.example; import com.surrealdb.Surreal; public class SurrealDB { public static void main(String[] args) { // Instantiate the driver try (final Surreal driver = new Surreal()) { // Connect to an in-memory database driver.connect("memory"); // Select a namespace and database driver.useNs("example").useDb("example"); // ... } } }
In order to represent database records within your application, you need to define POJO classes that match the tables in your database. Additionally, model classes require a public no-argument constructor to be used with the SDK.
For this example, we will create a Book
class representing book records in our database.
Book.javapackage me.yourname.surrealdb; import com.surrealdb.RecordId; import java.time.ZonedDateTime; public class Book { public RecordId id; public String title; public String author; public ZonedDateTime publishedAt; public boolean available; // A default constructor is required public Book() { } public Book(String title, String author, ZonedDateTime publishedAt, boolean available) { this.title = title; this.author = author; this.publishedAt = publishedAt; this.available = available; } public String toString() { return "Book{" + "id=" + id + ", title='" + title + '\'' + ", author='" + author + '\'' + ", publishedAt=" + publishedAt + ", available=" + available + '}'; } }
Model classes are extremely useful as they can be used to represent more than just tables, such as complex query responses, relations, and more. Additionally, the fields in model classes can contain nested objects, arrays, and other SurrealDB data types.
You can learn more about supported SurrealDB data types on the data types page.
The first step towards querying data is to populate the database with records. This can be achieved using the create
method, which allows you to pass model class instances to create new records.
In the following example, we instantiate a new Book
object and pass it to the create
method. This method will return a list of created Book
records, each with a unique record id.
// Create a new book Book book = new Book( "Aeon's Surreal Renaissance", "Dave MacLeod", ZonedDateTime.parse("2024-10-15T00:00:00Z"), true ); // Create a book record Book created = driver.create(Book.class, "book", book).get(0); // Print the record id System.out.println("Created a new book with id " + created.id);
Since create
allows us to create multiple records at once, it returns a list of books. In this case, we only created one book, so we use .get(0)
to retrieve it.
You might also want to create records with a specific ID. In this case, you can pass the RecordId
as the second argument to the create
method. This approach will return the Book
instance directly instead of a list.
// Create a book record with a custom id Book created = driver.create(Book.class, new RecordId("book", "aeon"), book);
Now we have records in our database, we can query them using the select
method. This method allows you to retrieve either all records from a table, or select a single record by its ID.
// Select all books Iterator<Book> books = driver.select(Book.class, "book"); while (books.hasNext()) { System.out.println("Found book: " + books.next().title); } // Select a specific book Optional<Book> aeon = driver.select(Book.class, new RecordId("book", "aeon")); aeon.ifPresent(value -> { System.out.println("Found book: " + value.title); });
While the select
method is useful for retrieving all records or a single record by ID, you may want to perform filtering, ordering, and other operations on your select queries. In these situations you can use the query
method to execute custom SurrealQL queries. We will cover this in the Complex queries section.
Records can be updated using the update
and upsert
methods. These methods allow you to update all records of a table, or a single record by its ID.
In the following example we update the availability status of a book record. We pass the id of the record we want to update, the type of update we want to perform, and the updated record. The UpType.MERGE
parameter tells the SDK to merge the updated record with the existing record, keeping any fields that are not present in the updated record.
After the update is applied, a new Book
instance is returned with the updated fields.
// Modify an existing book record existing.available = false; // Update the book record Book updated = driver.update(Book.class, existing.id, UpType.MERGE, existing); // Print the book status System.out.println("New availability: " + updated.available);
You can pass a table name instead of a record ID to update all records in a table. This will return an iterator of updated records.
// Create an empty book instance Book update = new Book(); update.available = true; // Update all book records Iterator<Book> updated = driver.update(Book.class, "book", UpType.MERGE, update);
As you can see, we can instantiate an empty Book
object and set only the fields we want to update. This allows us to conveniently update only specific fields.
Existing records can be deleted using the delete
method. You can either pass a table name to delete all records in a table, or a record ID to delete a specific record.
// Delete a specific book driver.delete(new RecordId("book", "aeon")); // Delete all book records driver.delete("book");
The Java SDK makes it easy to define relations between records using the relate
method. This method takes two RecordId
instances, an edge name, and an optional value model.
This next example demonstrates how to relate a book to a publisher.
RecordId bookId = new RecordId("book", "aeon"); RecordId publisherId = new RecordId("publisher", "surrealdb"); // Relate a book to a publisher driver.relate(bookId, "published_by", publisherId);
Much like other methods, you can also pass a class reference as a first argument to control the return and value type. This class must be a subclass of Relation
, or simply Relation
itself. This class holds the id
, in
, and out
of a relation.
Relation relation = driver.relate(Relation.class, bookId, "published_by", publisherId); System.out.println("Related " + relation.in + " to " + relation.out + " with relation " + relation.id);
While the previously mentioned methods are useful for basic operations, you may want to perform more complex queries. This can be achieved using the query
method, which allows you to execute custom SurrealQL queries.
You can pass a query string to the query
method and it will return a Response
object containing the query results.
Response response = driver.query("SELECT * FROM book WHERE available = true"); // Take the result of the first statement Value result = response.take(0);
You can optionally pass parameters to the query by using the queryBind
method, which takes a map of values to bind to the query.
Response response = driver.queryBind( "SELECT * FROM book WHERE available = $status", Map.of("status", true) ); // Take the result of the first statement Value result = response.take(0);
While we can represent object data using model classes, we can also use the Value
class to represent SurrealDB data types directly.
In all previous examples we can omit the model class reference arguments to make methods return a Value
instance instead of a model class instance. This class provides useful functions to check and convert data types, as well as access nested objects and arrays.
Value result = driver.query("RETURN 123").take(0); // Check if the result is a long before casting if (result.isLong()) { System.out.println("Long value: " + result.getLong()); }
Now that you have learned the basics of the SurrealDB SDK for Java, you can learn more about the API in the API documentation or explore the data types supported by the SDK.