Overview
The get() method retrieves a node by its ID. When a callback is provided, it enables reactive mode, automatically invoking the callback on any changes to the node.
Signature
await db.get(
id: string,
callback?: (node: Node | null) => void
): Promise<{ result: Node | null, unsubscribe?: () => void }>
Parameters
The unique identifier of the node to retrieve.
Optional callback function for reactive updates. Receives the full node object or null if deleted.Callback Parameters:
node: Node object with { id, value, edges, timestamp } or null
Return Value
The node object containing:
id (string): The nodeβs unique identifier
value (object): The nodeβs data content
edges (array): Connected relationships
timestamp (object): Hybrid Logical Clock timestamp with { physical, logical }
Returns null if the node doesnβt exist.
Function to stop listening for updates (only present in reactive mode).
Examples
Basic Retrieval
const { result } = await db.get("user:ana")
if (result) {
console.log("User name:", result.value.name)
console.log("Node ID:", result.id)
} else {
console.log("User not found")
}
Accessing Node Properties
const { result: user } = await db.get(userId)
if (user) {
console.log("Value:", user.value) // { type: "User", name: "Ana" }
console.log("Edges:", user.edges) // ["fileId1", "fileId2"]
console.log("Timestamp:", user.timestamp) // { physical: 1234567890, logical: 0 }
}
Reactive Mode - Listen for Changes
const { result, unsubscribe } = await db.get("user:ana", (node) => {
if (node) {
console.log("User updated:", node.value)
} else {
console.log("User was deleted")
}
})
// Initial state
console.log("Initial:", result.value)
// Later, stop listening
// unsubscribe()
Building a Live UI Component
class UserProfile {
constructor(userId) {
this.userId = userId
this.unsubscribe = null
}
async mount() {
const { result, unsubscribe } = await db.get(
this.userId,
(user) => this.render(user)
)
this.unsubscribe = unsubscribe
this.render(result) // Initial render
}
render(user) {
if (!user) {
document.getElementById("profile").innerHTML = "User not found"
return
}
document.getElementById("profile").innerHTML = `
<h1>${user.value.name}</h1>
<p>${user.value.bio || "No bio"}</p>
<p>Status: ${user.value.status || "offline"}</p>
`
}
unmount() {
if (this.unsubscribe) {
this.unsubscribe()
}
}
}
// Usage
const profile = new UserProfile("user:ana")
await profile.mount()
// Clean up when component is removed
// profile.unmount()
Checking Node Existence
const nodeExists = async (id) => {
const { result } = await db.get(id)
return result !== null
}
if (await nodeExists("task-123")) {
console.log("Task exists")
}
Following Graph Relationships
// Get a folder and its files
const { result: folder } = await db.get(folderId)
if (folder) {
console.log("Folder:", folder.value.name)
// Get all connected files
for (const fileId of folder.edges) {
const { result: file } = await db.get(fileId)
if (file) {
console.log(" - File:", file.value.name)
}
}
}
Real-Time Collaboration
// Monitor a shared document
const { unsubscribe } = await db.get(
"doc:shared-notes",
(doc) => {
if (!doc) return
// Update editor content when remote peer makes changes
editor.setValue(doc.value.content)
updateCollaboratorList(doc.value.lastEditedBy)
}
)
// When user edits locally
editor.on("change", async (content) => {
await db.put({
type: "Document",
content,
lastEditedBy: currentUser,
lastModified: Date.now()
}, "doc:shared-notes")
})
Handling Deleted Nodes
const { unsubscribe } = await db.get(taskId, (task) => {
if (task === null) {
console.log("Task was deleted")
removeTaskFromUI(taskId)
} else {
console.log("Task state:", task.value)
updateTaskInUI(task)
}
})
Combining with Promises
// Fetch multiple nodes in parallel
const [user, settings, preferences] = await Promise.all([
db.get("user:ana"),
db.get("settings:ana"),
db.get("preferences:ana")
])
console.log("User:", user.result?.value)
console.log("Settings:", settings.result?.value)
console.log("Preferences:", preferences.result?.value)
Reactive Subscriptions
Immediate Invocation: When using a callback, itβs invoked immediately with the current node state, then again on any subsequent changes.
Memory Leaks: Always call unsubscribe() when you no longer need updates to prevent memory leaks, especially in single-page applications:// In a component lifecycle
const { unsubscribe } = await db.get(id, callback)
// On component unmount/destroy
onCleanup(() => {
unsubscribe()
})
Node Structure
Every node returned by get() has this structure:
interface Node {
id: string // Unique identifier
value: object // Your data
edges: string[] // Array of linked node IDs
timestamp: {
physical: number // Unix timestamp in milliseconds
logical: number // Logical clock counter
}
}
- O(1) Lookup: Node retrieval by ID is constant time
- No Network Delay: Reads are always from local storage
- Reactive Efficiency: Subscriptions use internal event emitters with minimal overhead
Comparison with map()
| Feature | get() | map() |
|---|
| Lookup | By ID only | By query filters |
| Returns | Single node | Array of nodes |
| Reactive | Optional | Optional |
| Use case | Known ID | Search/filter |