- Roam uses Datascript (JavaScript/ClojureScript Datalog implementation)
- Each fact is a datom:
[entity-id attribute value transaction-id]
- Hidden ID: Internal database entity-id
- Public ID: Block reference (e.g.,
((GGv3cyL6Y))
) or page title ([[Page Title]]
)
:block/uid # Nine-character block reference
:create/email # Creator's email
:create/time # Creation timestamp
:edit/email # Editor's email
:edit/time # Last edit timestamp
:node/title # Page title (pages only)
:block/page # Reference to page entity-id
:block/order # Sequence within parent
:block/string # Block content
:block/parents # List of ancestor blocks
:children/view-type # 'bullet', 'document', 'numbered'
:block/heading # 1, 2, 3 for H1-H3
:block/props # Image/iframe sizing, slider position
:block/text-align # 'left', 'center', 'right', 'justify'
[:find (count ?title)
:where [_ :node/title ?title]]
[:find (count ?string)
:where [_ :block/string ?string]]
[:find ?ancestor (count ?block)
:in $ %
:where
[?ancestor :block/string]
[?block :block/string]
(ancestor ?block ?ancestor)]
[:find ?title:name ?title:uid ?time:date
:where
[?page :node/title ?title:name]
[?page :block/uid ?title:uid]
[?page :edit/time ?time:date]
[(clojure.string/starts-with? ?title:name "roam/")]]
[:find ?page_title:name ?page_title:uid
:in $ ?start_of_day %
:where
[?page :node/title ?page_title:name]
[?page :block/uid ?page_title:uid]
(ancestor ?block ?page)
[?block :edit/time ?time]
[(> ?time ?start_of_day)]]
[:find ?block_string
:where
[?p :node/title "Page Title"]
[?p :block/children ?c]
[?c :block/string ?block_string]]
[:find (pull ?e [*{:block/children [*]}])
:where [?e :node/title "Page Title"]]
let fragment = "search_term";
let query = `[:find ?title:name ?title:uid ?time:date
:where [?page :node/title ?title:name]
[?page :block/uid ?title:uid]
[?page :edit/time ?time:date]]`;
let results = window.roamAlphaAPI
.q(query)
.filter((item, index) => item[0].toLowerCase().indexOf(fragment) > 0)
.sort((a, b) => a[0].localeCompare(b[0]));
[:find ?namespace ?attribute
:where [_ ?attribute]
[(namespace ?attribute) ?namespace]]
- Use
:block/parents
for ancestors (includes all levels) - Use
:block/children
for immediate descendants only - Combine
clojure.string
functions for complex text matching - Use
distinct
to avoid duplicate results - Use Pull patterns for hierarchical data retrieval
- Handle case sensitivity in string operations carefully
- Chain ancestry rules for multi-level traversal
Available functions:
- clojure.string/includes?
- clojure.string/starts-with?
- clojure.string/ends-with?
- count
- <, >, <=, >=, =, not=, !=
Available functions:
- sum
- max
- min
- avg
- count
- distinct