Write Queries

💡

In the following sample code, db represents the state variable of your database instance. For reference, see Initialize WeaveDB

collection_name refers to the string value that contains the name of your collection, and doc_id refers to the string value that contains the unique identifier of a document from the collection.

💡

The differences between set, upsert, and update are:

  • set - if doc_id exists in the collection, it will override the entire document, deleting all previous properties or it will add a new document if doc_id does not exist.
  • update - if doc_id exists in the collection, it will merge the new data with the existing document or the query will fail if the assigned doc_id does not exist.
  • upsert - if doc_id exists in the collection, it will merge the new data with the existing document or it will add a new document if doc_id does not exist.

add

Adds a new document to the given collection.

add(data_JSON, collection_name)
await db.add({ age: 20, name: "Bob" }, collection_name)
💡

The document ID will be assigned in a random yet deterministic manner.

set

Adds a new document to the given collection and allows you to choose its document ID.

set(data_JSON, collection_name, doc_id)
await db.set({ age: 20, name: "Bob" }, collection_name, doc_id)
💡

This will reset the whole document if the doc_id already exists.

upsert

Combines the functions of update and set. It merges the new data with an existing document or creates a new document if it does not already exist.

upsert(data_JSON, collection_name, doc_id)
await db.upsert({ age: 20, name: "Bob" }, collection_name, doc_id)

update

Updates a specific document within a collection. This command only modifies existing documents and does not create new ones.

update(data_JSON, collection_name, doc_id)
await db.update({ age: 25 }, collection_name, doc_id)
💡

This will fail if the doc_id does not exist.

Special Operations

The following is a list of special operations. WeaveDB has shortcuts for common operations that are only available with the SDK and not with the web console terminal at the moment.

Delete a field

Removes a specified field from a document in a collection. Useful for cleaning up data or adhering to data structure changes.

await db.update({ age: db.del() }, collection_name, doc_id)

Increase a field

Increments the value of a numeric field in a document by a specified amount. Ideal for updating counters or cumulative values.

await db.update({ age: db.inc(5) }, collection_name, doc_id)

Decrease a field

Decrements the value of a numeric field in a document by a specified amount. Useful for decrementing counters or adjusting values downwards.

await db.update({ age: db.inc(-5) }, collection_name, doc_id)

Array union

Adds unique elements to an array field in a document. Prevents duplication and is useful for managing lists without redundant entries.

await db.update({ chars: db.union([ "a", "b", "c", "d" ]) }, collection_name, doc_id)

Array remove

Removes specified elements from an array field in a document. Ideal for filtering out unwanted items from a list.

await db.update({ chars: db.remove([ "b", "c" ]) }, collection_name, doc_id)

Set block timestamp

Sets the field to the current block timestamp.

await db.update({ date: db.ts() }, collection_name, doc_id)

Set signer Ethereum address

Sets the field to the signer's wallet address.

await db.update({ address: db.signer() }, collection_name, doc_id)
💡

signer will always be in lowercase if it's an EVM wallet address. WeaveDB contract converts everything to lowercase to use them internally.

In regard to Arweave wallet addresses, the case will be retained, because it's RSA hashes and the case matters.

data()

Replace a field with relayer's extra data

ℹ️

Feature added in contract version 0.28.12

// icon field will be automatically replaced with `image.png` from the relayer
const query = await db.sign(
  "update",
  { icon: db.data("extra_data_key") },
  collection_name,
  doc_id,
  { jobID: "jobID", evm: signer_wallet },
)
 
await db.relay("jobID", query, { extra_data_key: "image.png" }, { evm: relayer_wallet })

zkp()

ℹ️

Feature added in contract version 0.38.0

Verify Zero Knowledge Proof with PolygonID (opens in a new tab)

await db.update({ userID: db.zkp(proof, pub_signals) }, collection_name, doc_id)
 
/*
userID will be replaced with the following
you should modify it further in access control rules
 
{
  valid,
  pub_signals: {
    value,
    merklizedn,
    userID,
    issuerAuthState,
    requestID,
    issuerID,
    isRevocationChecked,
    issuerClaimNonRevState,
    timestamp,
    claimSchema,
    claimPathNotExists,
    claimPathKey,
    slotIndex,
    operator,
  },
}
*/

delete

Removes a specified document from a collection.

await db.delete(collection_name, doc_id)

batch

An atomic batch is a feature that allows you to perform multiple read and write operations as a single, atomic unit.

Atomic means that all the operations within the batch are either fully completed or completely aborted. If any of the write operations fail, none of the changes will be applied to the database, ensuring data integrity.

await db.batch([
  ["set", { name: "Bob" }, "people", "Bob"],
  ["upsert", { name: "Alice" }, "people", "Alice"],
  ["delete", "John"]
])
💡

You can use batch only if all the queries are by the same signer. If you have multiple signers, use bundle.

Admin queries can be batch-executed as well:

await db.batch([
  ["setSchema", schema, "people"],
  ["setRules", rules, "people"],
  ["addOwner", "0xABC"]
], { ar : admin_arweave_wallet })

bundle

Bundle multiple queries from multiple signers

const query1 = await db.sign("set", {name: "Bob"}, "people", "Bob", {evm: wallet1})
const query2 = await db.sign("set", {name: "Alice"}, "people", "Alice", {ii: wallet2})
const query3 = await db.sign("set", {name: "Beth"}, "people", "Beth", {ar: wallet3})
 
await db.bundle([query1, query2, query3], {ar: bundler_wallet})

sign

Sign a query without sending a transaction:

await db.sign("set", {name: "Bob", age: 20}, collection_name, doc_id)

relay

Relay a query allows for the execution of a signed operation with additional parameters. Useful for scenarios where you need to delegate the execution of a database operation, potentially with added data.

const param = await db.sign("set", {name: "Bob"}, collection_name, doc_id)
const extra = { age: 20 }
await db.relay("jobID", param, extra, {evm: relayer_wallet})