Roam's ability to create queries is where its power really begins to shine. Over time, you're going to build up quite a body of notes. What's more important is being able to pull out relevant entries at the right time, quickly and easily. Queries are one of the most effective ways to do this.
The syntax is a little esoteric, and there are a few little tips and tricks to creating effective queries.
First, what is a query exactly? Roam is a database, although it may not seem like it at first glance. Queries are just a way of asking a question to find specific pieces of information. In Roam, they are done using your tags and page references that you've applied to your note blocks.
The slash commands for queries give you a good starting point for straightforward inquiries. Understanding how they're constructed will enable you to bring together what you're looking for in more complex ways.
Let's start with the basic 3 operators. First is an OR query
{{ [[query]]: {or: [[mind garden]] [[digital garden]] [[digital gardening]] }}}
Here, I've created a query which is looking for any notes that have been tagged or reference "mind garden", "digital garden", or "digital gardening". I'll get all my notes back that contain any of these terms.
Contrast the same terms but with an AND query
{{ [[query]]: {and: [[mind garden]] [[digital garden]] [[digital gardening]] }}}
I'll only get back notes which have been tagged with all of those references.
You can combine both AND and OR operators to have finer control. For example, it's more likely that I've tagged notes with "mind garden" and either "digital garden" or "digital gardening" so to bring back notes according to that criteria, I'd use an AND OR query
{{ [[query]]: {and: [[mind garden]] {or: [[digital garden]] [[digital gardening]]} }}}
Finally, you can also exclude notes that have certain tags using the NOT operator. Generally, you're only going to use this in combination with the ANDs and ORs.
{{ [[query]]: {and: [[mind garden]] {not: [[digital garden]]]} }}}
This query is only looking for notes which I've added the tag "mind garden", but excluding notes that are also tagged with "digital garden".
While it's not listed on the Slash commands menu, there is also a BETWEEN operator. There's not much information available about it currently, but it allows you to do a basic query using dates where you have tagged a note with a dated page reference.
{{ [[query]]: {between: [[May 20th, 2020]] [[May 23rd, 2020]]} }}
Excluding other queries
The eagle-eyed amongst you may have noticed that when you choose a slash command query, the query
operator itself is wrapped in page reference brackets. If you've tried writing a query from scratch, you may have missed doing this, but your query still works just fine. It works either way, but getting into the habit of making [[query]]
itself a page reference is a best practice.
First, it gives you a page where all your queries can be found and brought together.
Second, and more helpfully, is that when you're creating queries, you can exclude other queries that you've created previously being included in your results.
You can see in my image where the top query isn't excluding the query in the block below it, cluttering the results.
You can find all your outstanding TODOs between a given date range. This relies on you having tagged your TODOs with a dated page reference.
{{ [[query]]: {and: [[TODO]] {not: [[query]]}{between: [[January 31st, 2020]][[May 8th, 2020]]}} }}
Having to continually alter the dates can be a little frustrating. One way to ease this is to use some form of text expansion snippets to generate the dates needed. I'll be covering more about this in the future. However, there is a hidden trick in Roam that gets you part-way there natively. But, right now, it only works on daily note pages. It doesn't work on a normal, typical page. When you're on a suitable page, you can create queries with dynamic placeholders like so:
{{ [[query]]: {and: [[TODO]] {not: [[query]]}{between: [[last month]][[yesterday]]}} }}
The dynamic placeholders you can use are today,yesterday, last week, last month, this month, and next month. They must be all lower-case and wrapped in page reference brackets. You can copy or move the query block from day-to-day, and it'll dynamically pull in the matching TODOs.
You can design a system of tagging TODOs to build your own GTD style workflows, and then create queries for TODOs with the tag combinations you need. As a simple illustration, in classic GTD you would assign contexts to your tasks for where you could work on them. e.g. #home or #office, or the type of task, e.g. #phonecall or #email. Let's also assume that you tag each TODO with the date you're planning to work on it too.
Example tasks showing how you can use inline and/or tagged references according to your preferences
{{ [[query]]: {and: [[TODO]] #call #office {not: [[query]]} } }}
This query shows you all the tasks tagged with call and office. One very important thing to note though. You must remember that the page references and tags are case-sensitive so in my example above, the query as written above will only find the latter TODO because the inline reference of "Call" in the first TODO is capitalised. To find all variations, you'd need to use an OR query to capture the "call" variants:
{{ [[query]]: {and: [[TODO]] #office {or: #call #Call} {not: [[query]]} } }}
For this reason, it is worth adopting some tag conventions that you can use consistently to avoid accidentally missing TODOs. We'll go into more depth on tagging strategies and conventions in a future lesson.
You can then go further and use the between operator to limit them to the specific dates. (Not forgetting that these will only work on the daily pages).
{{ [[query]]: {and: [[TODO]] #call #office {between: [[today]] [[last week]]} {not: [[query]]}} }}
In truth, I have found these dynamic date queries to be a bit finickity in practice, not always returning what I would expect with the date ranges, so I don't feel I can trust them and prefer to have the TODOs showing in the linked references for the day, and filter them with tags even though it doesn't remove the DONE tasks as the query version does.
A big reason many people are using Roam for research is to collect and make notes to work on over time. A writing inbox is a helpful way to gather these together. I have a page with a number of queries on that I use to find notes that I can work on. For example, I import highlights and comments on articles I read from Instapaper and tag them with INBOX
to process later, before they start moving through my progressive summarization steps.
{{ [[query]]: {and: [[Resonance Calendar]] #INBOX {not: [[query]]} } }}