Skip to main content

Transaction Syntax

Introduction

Transactions modify the data stored in Fluree. Transaction data is encoded as a JSON object and can be a JSON object or an array of objects.

Transaction objects come in two types, insert and delete, where insert and delete can be combined in the space of one transaction to perform surgical updates against data state.

Fluree treats transaction objects as JSON-LD, and any object that is not a delete object will be inserted as RDF triples in the database. Therefore, any valid JSON-LD object is a valid insert object.

You can, however, transact vanilla JSON that doesn't use JSON-LD conventions (such as @id or @type):


{
"ledger": "notable-people",
"insert": {
"name": "Shonda Rhimes"
}
}

JSON-LD keywords can, however, be used and will be interpreted according to their JSON-LD meaning:


{
"@context": {
"ex": "http://example.org/",
"schema": "http://schema.org/"
},
"ledger": "notable-people",
"insert": {
"@id": "ex:shonda-rhimes",
"schema:name": "Shonda Rhimes"
}
}

Arbitrarily nested JSON-LD is also supported:


{
"@context": {
"@base": "http://schema.org/",
"@vocab": "http://schema.org/"
},
"ledger": "media",
"insert": {
"@id": "https://www.wikidata.org/wiki/Q836821",
"@type": ["Movie"],
"name": "The Hitchhiker's Guide to the Galaxy",
"disambiguatingDescription": "2005 British-American comic science fiction film directed by Garth Jennings",
"titleEIDR": "10.5240/B752-5B47-DBBE-E5D4-5A3F-N",
"isBasedOn": {
"@id": "https://www.wikidata.org/wiki/Q3107329",
"@type": "Book",
"name": "The Hitchhiker's Guide to the Galaxy",
"isbn": "0-330-25864-8",
"author": {
"@id": "https://www.wikidata.org/wiki/Q42",
"@type": "Person",
"name": "Douglas Adams"
},
"isbn": "0-330-25864-8",
"name": "The Hitchhiker's Guide to the Galaxy"
},
"name": "The Hitchhiker's Guide to the Galaxy",
"titleEIDR": "10.5240/B752-5B47-DBBE-E5D4-5A3F-N"
}
}

See the W3C standard for JSON-LD for more information on structuring JSON-LD objects.

Multi-Value Properties: @set vs @list

In Fluree, properties can have multiple values. By default, multi-value properties use set semantics (@set), meaning values are unordered and unique. For ordered collections, use list semantics (@list).

Default Behavior: @set (Unordered)

By default, when you provide an array of values, Fluree treats them as an unordered set:


{
"ledger": "my-ledger",
"insert": {
"@id": "ex:movie1",
"ex:starring": ["Alice", "Bob", "Charlie"]
}
}

Set characteristics:

  • Unordered — Query results may return values in any order
  • Unique — Duplicate values are automatically deduplicated
  • Efficient — Optimized for membership testing and updates

When querying, the order of values is not guaranteed:


["Charlie", "Alice", "Bob"] // Order may vary

Ordered Collections: @list

When order matters, use the @list container. Define it in your context:


{
"@context": {
"ex": "http://example.org/",
"ex:playlist": {"@container": "@list"}
},
"ledger": "my-ledger",
"insert": {
"@id": "ex:myPlaylist",
"ex:playlist": ["Song A", "Song B", "Song C"]
}
}

List characteristics:

  • Ordered — Values maintain their sequence
  • Allows duplicates — The same value can appear multiple times
  • Atomic updates — Must replace entire list to modify

When querying, the order is preserved:


["Song A", "Song B", "Song C"] // Order guaranteed

Inline @list Syntax

You can also specify @list inline without modifying the context:


{
"ledger": "my-ledger",
"insert": {
"@id": "ex:recipe1",
"ex:steps": {
"@list": ["Preheat oven", "Mix ingredients", "Bake for 30 min"]
}
}
}

Lists with Object References

Lists can contain references to other entities:


{
"@context": {
"ex": "http://example.org/",
"ex:orderedFriends": {"@container": "@list"}
},
"ledger": "my-ledger",
"insert": [
{"@id": "ex:alice", "ex:name": "Alice"},
{"@id": "ex:bob", "ex:name": "Bob"},
{
"@id": "ex:charlie",
"ex:name": "Charlie",
"ex:orderedFriends": [
{"@id": "ex:alice"},
{"@id": "ex:bob"}
]
}
]
}

When to Use Each

Use CaseContainerReason
Tags, categories, roles@set (default)Order doesn't matter
Cast members, authors@set (default)Membership is what matters
Playlist, queue, steps@listSequence is important
Priority ranking@listPosition has meaning
History, log entries@listChronological order matters

Updating Lists vs Sets

Sets support incremental updates — you can add or remove individual values:


{
"ledger": "my-ledger",
"insert": {
"@id": "ex:movie1",
"ex:starring": ["Diana"]
}
}

This adds "Diana" to the existing cast without removing others.

Lists require full replacement — you cannot insert at a specific position:


{
"@context": {"ex:steps": {"@container": "@list"}},
"ledger": "my-ledger",
"where": {"@id": "ex:recipe1", "ex:steps": "?oldSteps"},
"delete": {"@id": "ex:recipe1", "ex:steps": "?oldSteps"},
"insert": {
"@id": "ex:recipe1",
"ex:steps": {
"@list": ["Preheat oven", "Grease pan", "Mix ingredients", "Bake for 30 min"]
}
}
}

Single Values

When a property has only one value, both @set and @list return the value directly (not wrapped in an array):


// Stored as @list with one item
{"ex:playlist": ["Only Song"]}
// Returns as single value
{"ex:playlist": "Only Song"}

Sample Data & Ledger

You can recreate and test each of the sample transactions in this page using the json objects below to create the "media" ledger and transact in your sample data.

Create Test Ledger "media"

{
"@context": {
"schema": "http://schema.org/",
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"insert": {
"@id": "wiki:Q836821",
"@type": [
"schema:Movie"
],
"schema:name": "The Hitchhiker's Guide to the Galaxy",
"schema:disambiguatingDescription": "2005 British-American comic science fiction film directed by Garth Jennings",
"schema:titleEIDR": "10.5240/B752-5B47-DBBE-E5D4-5A3F-N",
"schema:isBasedOn": {
"@id": "wiki:Q3107329",
"@type": "schema:Book",
"schema:name": "The Hitchhiker's Guide to the Galaxy",
"schema:isbn": "0-330-25864-8",
"schema:author": {
"@id": "wiki:Q42",
"@type": "schema:Person",
"schema:name": "Douglas Adams"
}
},
"ex:boxOfficeGross": "$5,128,935.00",
"ex:starring": "Andrew Johnson"
}
}

Transaction Object: Insert

Insert a Single Record

In this example we are inserting a new record to our "media" ledger for the book "The Phantom Tollbooth"


{
"@context": {
"schema": "http://schema.org/",
"wiki": "https://www.wikidata.org/wiki/"
},
"ledger": "media",
"insert": [
{
"@id": "wiki:The_Phantom_Tollbooth",
"@type": "schema:Book"
}
]
}

Insert Multiple Records

In this example we will insert two records, one for the book Hyperion, and the other for the animated series AEon Flux.


{
"@context": {
"schema": "http://schema.org/",
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"insert": [
{
"@id": "wiki:Hyperion_(Simmons_novel)",
"@type": "schema:Book"
},
{
"@id": "wiki:%C3%86on_Flux",
"@type": "ex:animatedSeries",
"schema:name": "AEon Flux",
"schema:description": "Such a weird awesome show"
}
]
}

Transaction object: delete

To delete a subject, the transaction object must include the "delete" key. We will also often use the where key to bind existing data to logic variables, and then use them to qualify the exact existing data to be retracted. For more on the where clause, see our Reference Doc on FlureeQL Syntax.

Deleting All Facts on a Subject

Delete all facts pertaining to the TV Show "AEon Flux":


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/"
},
"ledger": "media",
"where": {
"@id": "wiki:%C3%86on_Flux",
"?p": "?o"
},
"delete": {
"@id": "wiki:%C3%86on_Flux",
"?p": "?o"
}
}

Deleting Values on a Single Predicate for a Single Subject

If a subject has a name of "The Hitchhiker's Guide to the Galaxy", delete the value(s) of the schema:name predicate for that subject:


{
"@context": {
"schema": "http://schema.org/"
},
"ledger": "media",
"where": {
"@id": "?s",
"schema:name": "?name"
},
"values": ["?name", ["The Hitchhiker's Guide to the Galaxy"]],
"delete": {
"@id": "?s",
"schema:name": "?name"
}
}

Deleting All Subjects with a Particular Property

Delete all subjects that contain the property schema:description


{
"@context": {
"schema": "http://schema.org/"
},
"ledger": "media",
"where": {
"@id": "?s",
"schema:description": "?description",
"?p": "?o"
},
"delete": {
"@id": "?s",
"?p": "?o"
}
}

Deleting All Subjects with a Particular Value on a Particular Property

Delete all subjects with the @type property "schema":"Movie"


{
"@context": {
"schema": "http://schema.org/"
},
"ledger": "media",
"where": {
"@id": "?s",
"@type": "schema:Movie",
"?p": "?o"
},
"delete": {
"@id": "?s",
"?p": "?o"
}
}

Update Transactions

Unlike insert and delete, 'update' is not a transaction object in Fluree. However it is still possible perform updates to existing data, often using a combination of where, delete, and insert, or even the schema of the data itself, to build the logic necessary for each transaction.

Update Existing Value

To replace an existing value, first delete the existing value, and then insert your desired data.

caution

The below transaction is somewhat brittle. It will ONLY delete the existing value of "ex:boxOfficeGross" if the value in the delete statement matches the current data state. If the delete value contains a typo such as "$5,128,935", instead of replacing the "ex:boxOfficeGross" value with "$26,232,138.00", "ex:boxOfficeGross" will include both the new and existing values. See below for how to more dynamically and safely update existing data.


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"delete": {
"@id": "wiki:Q836821",
"ex:boxOfficeGross": "$5,128,935.00"
},
"insert": {
"@id": "wiki:Q836821",
"ex:boxOfficeGross": "$26,232,138.00"
}
}

Test Query

{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"from": "media",
"select": { "wiki:Q836821": ["ex:boxOfficeGross"] }
}

Update New OR Existing Value

If you don't know the specific value you are replacing in your data, or if you don't know if a subject/predicate exists to begin with, or if you want to minimize the risk of human error, you can write a value-agnostic transaction.

First, use where to search for any existing value, then delete to get rid of that value, and then insert our new value. Here is an example:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "wiki:Q836821",
"ex:starring": "?star"
},
"delete": {
"@id": "wiki:Q836821",
"ex:starring": "?star"
},
"insert": {
"@id": "wiki:Q836821",
"ex:starring": "Martin Freeman"
}
}

Test Query

{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"from": "media",
"select": { "wiki:Q836821": ["ex:starring"] }
}

Update Nested Data

To upsert new nested data you can include the full JSON-LD upsert in your transaction like so:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "?s",
"name": "The Hitchhiker's Guide to the Galaxy"
},
"insert": {
"@id": "?s",
"ex:starring": "Martin Freeman",
"ex:alsoAppearsIn": {
"@id": "wiki:Sherlock_(TV_series)",
"name": "Sherlock",
"@type": ["TV Series"],
"ex:starring": "Martin Freeman",
"ex:alsoAppearsIn": {
"@id": "wiki:Q836821"
}
}
}
}

However, there is a risk in the above transaction that no entities get bound to ?s. When inserting nested data, if any parent nodes are dependent on a binding from the "where" clause (in this case "?s"), and if ?s fails to resolve to any existing entities, then nested / children data won't be transacted if the parent data isn't transacted first.

To avoid this you can transact nested data as siblings, as demonstrated in the following example:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "?s",
"name": "The Hitchhiker's Guide to the Galaxy"
},
"insert": [
{
"@id": "?s",
"ex:starring": "Martin Freeman",
"ex:alsoAppearsIn": { "@id": "wiki:Sherlock_(TV_series)" }
},
{
"@id": "wiki:Sherlock_(TV_series)",
"name": "Sherlock",
"@type": ["TV Series"],
"ex:starring": "Martin Freeman",
"ex:alsoAppearsIn": {
"@id": "wiki:Q836821"
}
}
]
}

By inserting our data as siblings, we can ensure that even if the data dependent on ?s fails to be inserted, the data that is not dependent on ?s will still be inserted.

Test Query

{
"@context": {
"ex": "http://example.org/"
},
"from": "media",
"select": {
"?s": [
"ex:starring",
"ex:alsoAppearsIn"
]
},
"where": {
"@id": "?s",
"ex:starring": "?star"
}
}

Update Multi-Cardinality Data

In order to entirely retract-and-replace a set of values on a multi-cardinality property, you can do the following:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "wiki:Q836821",
"ex:starring": "?anyValues"
},
"delete": {
"@id": "wiki:Q836821",
"ex:starring": "?anyValues"
},
"insert": {
"@id": "wiki:Q836821",
"ex:starring": [
"Martin Freeman",
"Sam Rockwell",
"Mos Def",
"Zooey Deschanel",
"Bill Nighy",
"Alan Rickman",
"Anna Chancellor",
"John Malkovich"
]
}
}

Test Query

{
"@context": {
"ex": "http://example.org/"
},
"from": "media",
"select": {
"?s": [
"ex:starring"
]
},
"where": {
"@id": "?s",
"ex:starring": "?star"
}
}

Append to Array

If you only want to append new values to an array in your transaction, you can use the insert term like this:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"insert": {
"@id": "wiki:Q836821",
"ex:starring": ["Bill Nye"]
}
}

Test Query

{
"@context": {
"ex": "http://example.org/",
"wiki": "https://www.wikidata.org/wiki/"
},
"from": "media",
"select": { "wiki:Q836821": ["ex:starring"] }
}

Only Update a Specific Array

You can also use a where clause to only upsert to a set of values if those values contain a value or values of interest:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "wiki:Q836821",
"ex:starring": "?stars"
},
"values": ["?stars", ["Martin Freeman"]],
"delete": {
"@id": "wiki:Q836821",
"ex:starring": "?stars"
},
"insert": {
"@id": "wiki:Q836821",
"ex:starring": [
"Martin Freeman",
"Sam Rockwell",
"Mos Def",
"Zooey Deschanel",
"Bill Nighy",
"Alan Rickman",
"Anna Chancellor",
"John Malkovich"
]
}
}

Test Query

{
"@context": {
"ex": "http://example.org/",
"wiki": "https://www.wikidata.org/wiki/"
},
"from": "media",
"select": { "wiki:Q836821": ["ex:starring"] }
}

Update Ordered Lists

Syntactically, updating ordered lists is exactly the same as unordered lists. As of right now, Fluree does not enable upserting data to a specific location within an ordered list. Instead users must delete the existing list and replace it with desired data, in the desired order.

Here is an example of how this transaction could look:


{
"@context": {
"wiki": "https://www.wikidata.org/wiki/",
"ex": "http://example.org/"
},
"ledger": "media",
"where": {
"@id": "wiki:Q836821",
"ex:starring": "?values"
},
"delete": {
"@id": "wiki:Q836821",
"ex:starring": "?values"
},
"insert": {
"@id": "wiki:Q836821",
"ex:starring": {
"@container": "@list",
"@value": ["Jean Paul Sartre", "Frederick Neitzche", "Simone De Beauvoir"]
}
}
}

Test Query

{
"@context": {
"ex": "http://example.org/",
"wiki": "https://www.wikidata.org/wiki/"
},
"from": "media",
"select": { "wiki:Q836821": ["ex:starring"] }
}