Skip to main content

Query APIs

WeaveDB queries cover most of the things Firestore can do with syntactic sugar inspired by Firestore Sweet.

getInfo

Get configurations

await db.getInfo()

getHash

Get current hash of chained txs.

info

WeaveDB contracts keep track of valid transactions by hashing chained txIds like blockchain.
latest_hash = hash( [ last_hash, current_txId ] )

await db.getHash()

getNonce

To get the next nonce for an address. Nonces are internally used for signature verification to write data.

await db.getNonce("address")

get / cget

get only returns data, whereas cget returns metadata of the docs too.

{ id, setter, data, block: { height, timestamp } }

The metadata returned with cget functions as a cursor for pagination.

Get a doc

await db.get(collection_name, doc_id)
await db.cget(collection_name, doc_id)

Get a collection

await db.get(collection_name)
await db.cget(collection_name)

Get a sub collection

Arbitrary length of document nesting is possible.

await db.get(collection_name, doc_id, sub_collection_name_1, sub_doc_id_1, sub_collection_name_2)

Limit

await db.get(collection_name, 5)

Sort

await db.get(collection_name, [ "age" ])
await db.get(collection_name, [ "age", "desc" ])
await db.get(collection_name, [ "age", "desc" ], [ "name", "asc" ])

Where

await db.get(collection_name, ["age"], [ "age", ">", 20 ])

== > >= < <= != in not-in array-contains array-contains-any are supported.

info

Dot notation can be used to specify nested object fields. (e.g. [ "favorites.food", "==", "apple" ])

Note that dot notation only works with where for now.

deprecated

= is deprecated and replaced by == at v0.23.0. You can still use it for backward compatibility.

Skip

await db.get(collection_name, [ "age" ], [ "startAfter", 20 ], [ "endAt", 60 ])
await db.get(collection_name, [ "age" ], [ "name", "desc" ], [ "startAfter", 20, "Bob" ])

startAt startAfter endAt endAfter are supported.

Pagination

const docs_page1 = db.cget(collection_name, [ "age" ])

const docs_page2 = db.cget(
collection_name,
["age"],
["startAfter", docs_page1[docs_page1.length - 1]]
)

on / con

You can subscribe to state changes with on and con. They are the counterparts of get and cget respectively.

These only work with weavedb-sdk-node for now.

const unsubscribe = await on.(collection_name, doc_id, (data) => {
console.log(data)
unsubscribe()
})

getCache / cgetCache

They are the same as get / cget, but get values from the cached state, which is faster but may not be the most up-to-date values.

These only work with weavedb-sdk-node for now.

await db.getCache(collection_name, doc_id)
await db.cgetCache(collection_name, doc_id)

listCollections

List collection names

await db.listCollections() // list root collections
await db.listCollections(collection_name, doc_id) // list sub collections

nocache

With weavedb-client and weavedb-node-client, if the last argument is boolean, it's recognized as nocache option.

gRPC nodes use getCache / cgetCache to get data by default, but the up-to-date values can be obtained with nocache option set true.

You would use nocache after updating data to get the latest values.

await db.set({ field : "value"}, collection_name, doc_id)
await db.get(collection_name, doc_id, true) // without true, the data might be old

add

Add a doc

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

The doc id will be randomly yet deterministically assigned.

getIds

To get the last added doc id, use getIds.

const tx = await db.add({ age: 20, name: "Bob" }, collection_name)
const doc_id = (await db.getIds(tx))[0]

set

Set a doc

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

upsert

Upsert a doc

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

update

Update a doc

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

del()

Delete a field

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

inc()

Increase/Decrease a field

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

union()

Array union

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

remove()

Array remove

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

ts()

Set block timestamp

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

signer()

Set signer Ethereum address

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

data()

Replace a field with relayer's extra data

// 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()

Verify Zero Knowledge Proof with PolygonID

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

Delete a doc

await db.delete(collection_name, doc_id)

batch

Atomic batch write from a single signer

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

Admin queries can be batch-executed as well

await db.batch([
["setSchema", schema, "people"],
["setRules", rules, "people"],
["addOwner", "0xABC"]
], { ar : admin_arweave_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

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})

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})

// bundle query needs no signer wallet
await db.bundle([query1, query2, query3])

setBundlers / getBundlers

Restrict bundlers, if bundlers are set, no one else but bundlers can write to the DB

await db.setBundlers([ BUNDLER_ADDRESS_1, BUNDLER_ADDRESS_2 ], {evm : admin_wallet})
// now only bundle queries can be accepted

await db.getBundlers()
// return bundlers, if empty, anyone can execute bundle queries
info

Restricting bundlers is useful to make queries consistent with low latencies via a rollup node.