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.