The `rlowdb` class provides a lightweight, JSON-based database solution for storing and managing structured data in R. It supports CRUD operations (Create, Read, Update, Delete) and enables querying with custom functions.
Methods
Method new()
Initialize the database, loading data from a JSON file. If the file does not exist, an empty database is created.
Arguments
file_path
The path to the JSON file that stores the database.
default_values
A list of named list with the format: list(collection_name = list(key_name_1 = value, key_name_2 = value, ..., key_name_n = value)) containing the default values that will be inserted each time the `insert` method is called. Note that the default_values will not override the existing records. Default is an empty list (`list()`).
auto_commit
whether to update the DB automatically each time there's an insertion, an update or a deletion. Defaults to TRUE.s Note that you can use the `commit` method to update the DB manually.
verbose
If TRUE, will print informative messages to the console. Defaults to FALSE
pretty
Use pretty = FALSE for compact JSON, which is more efficient for data transmission and storage. TRUE for a human readable format. Defaults to FALSE.
Method insert()
Insert a new record into a specified collection.
Method find()
Find records in a collection that match a given key-value pair.
Method update()
Update existing records in a collection.
Method upsert()
If a record exists, update it; otherwise, insert a new record. Note that in order to use the method, the 'collection' has to exist
Method delete()
Delete records from a collection that match a given key-value pair.
Method query()
Query a collection using a condition string. This function allows filtering records from a collection using a condition string that is evaluated dynamically. The condition supports multiple logical expressions using standard R operators (e.g., `>`, `<`, `==`, `&`, `|`).
Arguments
collection
The collection name (a string).
condition
A string representing a logical condition for filtering records. - Supports comparisons (`>`, `<`, `>=`, `<=`, `==`, `!=`). - Allows logical operators (`&` for AND, `|` for OR). - Example: `"views > 200 & id > 2"`. - If `NULL` or an empty string (`""`), returns all records.
Examples
db <- rlowdb$new("database.json")
db$insert("posts", list(id = 1, title = "LowDB in R", views = 100))
db$insert("posts", list(id = 2, title = "Data Management", views = 250))
db$insert("posts", list(id = 3, title = "Advanced R", views = 300))
# Query posts with views > 200 AND id > 2
db$query("posts", "views > 200 & id > 2")
# Query posts with views > 100 OR id == 1
db$query("posts", "views > 100 | id == 1")
# Query all posts (no condition)
db$query("posts", "")
unlink("database.json")
Method filter()
Filter Records Using a Custom Function This method applies a user-defined function to filter records in a specified collection. The function should take a record as input and return `TRUE` for records that should be included in the result and `FALSE` for records that should be excluded.
Method drop()
Just like DROP TABLE in SQL, drops a complete collection.
Method transaction()
Perform a Transaction with Rollback on Failure
This method executes a sequence of operations as a transaction. If any operation fails, it rolls back all changes to maintain data integrity.
Arguments
transaction_fn
A function that performs operations on `self`. It should not return a value.
Examples
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$count("users")
db$transaction(function() {
db$insert("users", list(name = "Zlatan", age = 40))
db$insert("users", list(name = "Neymar", age = 28))
# if an error is raised, a rollback will happen and
# the records won't be inserted
})
db$count("users")
unlink("database.json")
Method search()
Search Records in a Collection
This method searches for records in a collection where a specified key's value contains a given search term.
Arguments
collection
A character string specifying the name of the collection.
key
A character string specifying the field to search within.
term
A character string specifying the term to search for.
ignore.case
A logical value indicating whether the search should be case-insensitive (default: `FALSE`).
Examples
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$insert("users", list(id = 2, name = "Bob"))
db$insert("users", list(id = 3, name = "alice"))
# Case-sensitive search
db$search("users", "name", "Alice", ignore.case = FALSE)
# Case-insensitive search
db$search("users", "name", "alice", ignore.case = TRUE)
unlink("database.json")
Method bulk_insert()
Insert Multiple Records into a Collection
This method inserts multiple records into a specified collection at once. Each record should be a named list representing an entry in the collection.
Method rename_collection()
Allows you to rename an existing collection in the database. It checks if the specified collection exists before attempting to rename it.
Arguments
collection_name
A character string representing the current name of the collection to be renamed.
new_collection_name
A character string representing the new name for the collection.
Method list_keys()
Retrieves the names (keys) of all keys within a given collection.
Method count_values()
Count Occurrences of a Key's Values in a Collection
Method insert_default_values()
Add Default Values to Records in a Collection
Ensures that all records in a collection have specific default values for certain keys. If a key is missing, the default value is added. Optionally, existing values can be replaced with defaults.
Arguments
collection
The collection name.
defaults
A named list of default values to add.
replace_existing
Logical; if `TRUE`, replaces existing values with defaults. If `FALSE`, only adds missing keys. Defaults to `FALSE`.
Examples
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(name = "Alice", age = 30),
list(name = "Bob"),
list(name = "Charlie", age = 25, role = "admin")
))
# Add defaults without replacing existing values
db$insert_default_values("users", list(role = "guest", active = TRUE))
# Add defaults and replace existing values
db$insert_default_values("users", list(role = "guest", active = TRUE), replace_existing = TRUE)
unlink("database.json")
Method clone_collection()
Clone an existing collection to a new collection with a different name. This creates an exact copy of the original collection's records under the new name.
Method sample_records()
Randomly sample records from a collection
Arguments
collection
The name of the collection to sample from
n
Number of records to sample. If n > collection size, returns all records with a warning.
replace
Should sampling be with replacement? Default FALSE
seed
Optional random seed for reproducible sampling
Examples
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$insert("users", list(id = 2, name = "Bob"))
db$insert("users", list(id = 3, name = "Charlie"))
# Sample 2 records without replacement
db$sample_records("users", n = 2)
# Sample with replacement
db$sample_records("users", n = 5, replace = TRUE)
# Reproducible sampling with seed
db$sample_records("users", n = 2, seed = 123)
unlink("database.json")
Method set_schema()
Set schema for a collection to validate future inserts/updates
Arguments
collection
The collection name
schema
A named list where: - Names are field names - Values can be: * A type string ("character", "numeric", etc.) * A function that returns TRUE/FALSE * A vector of allowed values * NULL to make the field optional
Examples
db <- rlowdb$new("database.json")
# Define schema before inserting
db$set_schema("users", list(
id = "numeric",
name = function(x) is.character(x) && nchar(x) > 0,
age = function(x) is.numeric(x) && x >= 0,
email = NULL # Optional
))
# This will fail validation:
try(db$insert("users", list(id = "1", name = "")))
Examples
## ------------------------------------------------
## Method `rlowdb$get_data`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$get_data()
#> $users
#> $users[[1]]
#> $users[[1]]$id
#> [1] 1
#>
#> $users[[1]]$name
#> [1] "Alice"
#>
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$get_data_collection`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$get_data_collection("users")
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$name
#> [1] "Alice"
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$get_data_key`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$insert("users", list(id = 2, name = "Omar"))
db$get_data_key("users", "name")
#> [1] "Alice" "Omar"
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$insert`
## ------------------------------------------------
db <- rlowdb$new("database.json", default_values = list(
"users" = list("active" = TRUE)
)
)
db$insert("users", list(id = 1, name = "Alice"))
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$find`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$find("users", "id", 1)
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$name
#> [1] "Alice"
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$update`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$update("users", "id", 1, list(name = "Alice Updated"))
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$upsert`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 100, name = "Coconut"))
db$upsert("users", "id", 1, list(name = "Alice Updated"))
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$delete`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$delete("users", "id", 1)
db$get_data()
#> $users
#> list()
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$query`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("posts", list(id = 1, title = "LowDB in R", views = 100))
db$insert("posts", list(id = 2, title = "Data Management", views = 250))
db$insert("posts", list(id = 3, title = "Advanced R", views = 300))
# Query posts with views > 200 AND id > 2
db$query("posts", "views > 200 & id > 2")
#> [[1]]
#> [[1]]$id
#> [1] 3
#>
#> [[1]]$title
#> [1] "Advanced R"
#>
#> [[1]]$views
#> [1] 300
#>
#>
# Query posts with views > 100 OR id == 1
db$query("posts", "views > 100 | id == 1")
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$title
#> [1] "LowDB in R"
#>
#> [[1]]$views
#> [1] 100
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 2
#>
#> [[2]]$title
#> [1] "Data Management"
#>
#> [[2]]$views
#> [1] 250
#>
#>
#> [[3]]
#> [[3]]$id
#> [1] 3
#>
#> [[3]]$title
#> [1] "Advanced R"
#>
#> [[3]]$views
#> [1] 300
#>
#>
# Query all posts (no condition)
db$query("posts", "")
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$title
#> [1] "LowDB in R"
#>
#> [[1]]$views
#> [1] 100
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 2
#>
#> [[2]]$title
#> [1] "Data Management"
#>
#> [[2]]$views
#> [1] 250
#>
#>
#> [[3]]
#> [[3]]$id
#> [1] 3
#>
#> [[3]]$title
#> [1] "Advanced R"
#>
#> [[3]]$views
#> [1] 300
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$filter`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("users", list(name = "Gamma", age = 36))
# Find users older than 30
db$filter("users", function(record) record$age > 30)
#> [[1]]
#> [[1]]$name
#> [1] "Gamma"
#>
#> [[1]]$age
#> [1] 36
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$drop`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$drop("users")
db$get_data()
#> named list()
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$drop_all`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$drop_all()
db$get_data()
#> named list()
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$clear`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$clear("users")
db$get_data()
#> $users
#> list()
#>
#> $consumers
#> $consumers[[1]]
#> $consumers[[1]]$name
#> [1] "Teta"
#>
#> $consumers[[1]]$age
#> [1] 22
#>
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$count`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("users", list(name = "Gamma", age = 36))
db$count("users")
#> [1] 2
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$list_collections`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$list_collections()
#> [1] "users" "consumers"
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$exists_collection`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$exists_collection("users")
#> [1] TRUE
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$exists_key`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$exists_key("users", "name")
#> [1] TRUE
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$exists_value`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$insert("consumers", list(name = "Teta", age = 22))
db$exists_value("users", "name", "Delta")
#> [1] TRUE
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$transaction`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(name = "Delta", age = 25))
db$count("users")
#> [1] 1
db$transaction(function() {
db$insert("users", list(name = "Zlatan", age = 40))
db$insert("users", list(name = "Neymar", age = 28))
# if an error is raised, a rollback will happen and
# the records won't be inserted
})
db$count("users")
#> [1] 3
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$search`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$insert("users", list(id = 2, name = "Bob"))
db$insert("users", list(id = 3, name = "alice"))
# Case-sensitive search
db$search("users", "name", "Alice", ignore.case = FALSE)
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$name
#> [1] "Alice"
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 3
#>
#> [[2]]$name
#> [1] "alice"
#>
#>
# Case-insensitive search
db$search("users", "name", "alice", ignore.case = TRUE)
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$name
#> [1] "Alice"
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 3
#>
#> [[2]]$name
#> [1] "alice"
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$bulk_insert`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(id = 1, name = "Alice", age = 25),
list(id = 2, name = "Bob", age = 32),
list(id = 3, name = "Charlie", age = 40)
))
db$count("users")
#> [1] 3
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$rename_collection`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(id = 1, name = "Alice", age = 25),
list(id = 2, name = "Bob", age = 32),
list(id = 3, name = "Charlie", age = 40)
))
db$list_collections()
#> [1] "users"
db$rename_collection("users", "customers")
db$list_collections()
#> [1] "customers"
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$list_keys`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(id = 1, name = "Alice", age = 25),
list(id = 2, name = "Bob", age = 32),
list(id = 3, name = "Charlie")
))
db$list_keys("users")
#> [1] "id" "name" "age"
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$count_values`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(id = 1, name = "Alice", age = 25),
list(id = 2, name = "Bob", age = 32),
list(id = 3, name = NA),
list(id = 4, name = NA)
))
db$count_values("users", "name")
#> count
#> Alice Bob <NA>
#> 1 1 2
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$insert_default_values`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$bulk_insert("users", list(
list(name = "Alice", age = 30),
list(name = "Bob"),
list(name = "Charlie", age = 25, role = "admin")
))
# Add defaults without replacing existing values
db$insert_default_values("users", list(role = "guest", active = TRUE))
# Add defaults and replace existing values
db$insert_default_values("users", list(role = "guest", active = TRUE), replace_existing = TRUE)
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$clone_collection`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$clone_collection("users", "users_backup")
db$list_collections()
#> [1] "users" "users_backup"
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$sample_records`
## ------------------------------------------------
db <- rlowdb$new("database.json")
db$insert("users", list(id = 1, name = "Alice"))
db$insert("users", list(id = 2, name = "Bob"))
db$insert("users", list(id = 3, name = "Charlie"))
# Sample 2 records without replacement
db$sample_records("users", n = 2)
#> [[1]]
#> [[1]]$id
#> [1] 1
#>
#> [[1]]$name
#> [1] "Alice"
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 3
#>
#> [[2]]$name
#> [1] "Charlie"
#>
#>
# Sample with replacement
db$sample_records("users", n = 5, replace = TRUE)
#> [[1]]
#> [[1]]$id
#> [1] 3
#>
#> [[1]]$name
#> [1] "Charlie"
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 1
#>
#> [[2]]$name
#> [1] "Alice"
#>
#>
#> [[3]]
#> [[3]]$id
#> [1] 2
#>
#> [[3]]$name
#> [1] "Bob"
#>
#>
#> [[4]]
#> [[4]]$id
#> [1] 3
#>
#> [[4]]$name
#> [1] "Charlie"
#>
#>
#> [[5]]
#> [[5]]$id
#> [1] 3
#>
#> [[5]]$name
#> [1] "Charlie"
#>
#>
# Reproducible sampling with seed
db$sample_records("users", n = 2, seed = 123)
#> [[1]]
#> [[1]]$id
#> [1] 3
#>
#> [[1]]$name
#> [1] "Charlie"
#>
#>
#> [[2]]
#> [[2]]$id
#> [1] 1
#>
#> [[2]]$name
#> [1] "Alice"
#>
#>
unlink("database.json")
## ------------------------------------------------
## Method `rlowdb$set_schema`
## ------------------------------------------------
db <- rlowdb$new("database.json")
# Define schema before inserting
db$set_schema("users", list(
id = "numeric",
name = function(x) is.character(x) && nchar(x) > 0,
age = function(x) is.numeric(x) && x >= 0,
email = NULL # Optional
))
# This will fail validation:
try(db$insert("users", list(id = "1", name = "")))
#> Error in private$.validate_record(collection, record) :
#> Schema validation failed for collection 'users':
#> - Key 'id' must be type 'numeric' (got 'character')
#> - Key 'name' failed validation
#> - Missing required field: 'age'