Files
obsidian-workflow-template/_Sources/2023-07-31/Grouping - Tasks User Guide - Obsidian Publish.md
Mathis Gauthey f366d5b7b6 Initial commit
2023-08-05 19:14:53 +01:00

550 lines
26 KiB
Markdown

---
id: id-generated-by-omnivore
title: Grouping - Tasks User Guide - Obsidian Publish
tags:
- obsidian-tasks
state: ARCHIVED
date_saved: 2023-07-16 10:23:40
date_read: 2023-07-16 12:18:14
date_archived: 2023-07-16T10:05:16.592Z
---
# Grouping - Tasks User Guide - Obsidian Publish
#Omnivore
[Read on Omnivore](https://omnivore.app/)
[Read Original](https://publish.obsidian.md/tasks/Queries/Grouping)
## Webpage
## Grouping
## Contents
This page is long. Here are some links to the main sections:
* [Basics](https://publish.obsidian.md/tasks/Queries/Grouping#Basics)
* [Custom Groups](https://publish.obsidian.md/tasks/Queries/Grouping#Custom%20Groups)
* [Group by Task Statuses](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Task%20Statuses)
* [Group by Dates in Tasks](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Dates%20in%20Tasks)
* [Group by Other Task Properties](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20Other%20Task%20Properties)
* [Group by File Properties](https://publish.obsidian.md/tasks/Queries/Grouping#Group%20by%20File%20Properties)
* [Multiple groups](https://publish.obsidian.md/tasks/Queries/Grouping#Multiple%20groups)
* [Refining groups](https://publish.obsidian.md/tasks/Queries/Grouping#Refining%20groups)
* [Notes](https://publish.obsidian.md/tasks/Queries/Grouping#Notes)
* [Screenshots](https://publish.obsidian.md/tasks/Queries/Grouping#Screenshots)
* [Examples](https://publish.obsidian.md/tasks/Queries/Grouping#Examples)
## Basics
Introduced in Tasks 1.6.0.
By default, Tasks displays tasks in a single list.
To divide the matching tasks up with headings, you can add `group by` lines to the query.
## Custom Groups
`group by function` was introduced in Tasks 4.0.0.
Tasks provides many built-in grouping options, but sometimes they don't quite do what is wanted by all users.
Now Tasks has a powerful mechanism for you to create your own **custom groups**, offering incredible flexibility.
There are many examples of the custom grouping instruction `group by function` in the documentation below, with explanations, for when the `group by` instructions built in to Tasks do not satisfy your preferences.
You can find out more about this very powerful facility in [Custom Grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping).
## Group by Task Statuses
For more information, including adding your own customised statuses, see [Statuses](https://publish.obsidian.md/tasks/Getting+Started/Statuses).
### Status
* `group by status` (Done or Todo, which is capitalized for visibility in the headings)
* Note that the Done group is displayed before the Todo group, which differs from the Sorting ordering of this property.
* `Done` is used for tasks status types `DONE`, `CANCELLED` and `NON_TASK`
* `Todo` is used for status types with type `TODO` and `IN_PROGRESS`
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status** is now possible.
* `group by function task.isDone ? "Action Required" : "Nothing To Do"`
* Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.
### Status Name
* `group by status.name`
* This groups by the names you give to your custom statuses, in alphabetical order.
`group by status.name` was introduced in Tasks 1.23.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status names** is now possible.
* `group by function task.status.name`
* Identical to "group by status.name".
* `group by function task.status.name.toUpperCase()`
* Convert the status names to capitals.
### Status Type
* `group by status.type`
* This groups by the types you have given to your custom statuses.
* The groups will appear in this order, and with these group names:
* `IN_PROGRESS`
* `TODO`
* `DONE`
* `CANCELLED`
* `NON_TASK`
`group by status.type` was introduced in Tasks 1.23.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status types** is now possible.
* `group by function task.status.type`
* Unlike "group by status.type", this sorts the status types in alphabetical order.
### Status Symbol
There is no built-in instruction to group by status symbols.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by status symbol** is now possible.
* `group by function "Status symbol: " + task.status.symbol.replace(" ", "space")`
* Group by the status symbol, making space characters visible.
### Next Status Symbol
There is no built-in instruction to group by next status symbols.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by next status symbol** is now possible.
* `group by function "Next status symbol: " + task.status.nextSymbol.replace(" ", "space")`
* Group by the next status symbol, making space characters visible.
## Group by Dates in Tasks
### Due Date
* `group by due`
* The due date of the task, including the week-day, or `No due date`.
* `due` grouping option was introduced in Tasks 1.7.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by due date** is now possible.
These examples all use `task.due` property, which is a `TasksDate` object. You can see the current [TasksDate source code](https://github.com/obsidian-tasks-group/obsidian-tasks/blob/main/src/Scripting/TasksDate.ts), to explore its capabilities.
* `group by function task.due.format("YYYY-MM-DD dddd")`
* Like "group by due", except it uses no heading, instead of a heading "No due date", if there is no due date.
* `group by function task.due.formatAsDate()`
* Format date as YYYY-MM-DD or empty string (so no heading) if there is no due date.
* `group by function task.due.formatAsDateAndTime()`
* Format date as YYYY-MM-DD HH:mm or empty string if no due date.
* Note:
* This is shown for demonstration purposes.
* Currently the Tasks plugin does not support storing of times.
* Do not add times to your tasks, as it will break the reading of task data.
* `group by function task.due.format("YYYY[%%]-MM[%%] MMM", "no due date")`
* Group by month, for example `2023%%-05%% May` ...
* ... which gets rendered by Obsidian as `2023 May`.
* Or show a default heading "no due date" if no date.
* The hidden month number is added, commented-out between two `%%` strings, to control the sort order of headings.
* To escape characters in format strings, you can wrap the characters in square brackets (here, `[%%]`).
* `group by function task.due.format("YYYY[%%]-MM[%%] MMM [- Week] WW")`
* Group by month and week number, for example `2023%%-05%% May - Week 22` ...
* ... which gets rendered by Obsidian as `2023 May - Week 22`.
* If the month number is not embedded, in some years the first or last week of the year is displayed in a non-logical order.
DON'T PANIC! For users who are comfortable with JavaScript, these more complicated examples may also be of interest:
* `group by function task.due.moment?.fromNow() || ""`
* Group by the time from now, for example "8 days ago".
* Because Moment.fromNow() is not provided by TasksDate, we need special code for when there is no date value.
* Whilst interesting, the alphabetical sort order makes the headings a little hard to read.
* `group by function task.due.format("dddd")`
* Group by day of the week (Monday, Tuesday, etc).
* The day names are sorted alphabetically.
* `group by function task.due.format("[%%]d[%%]dddd")`
* Group by day of the week (Sunday, Monday, Tuesday, etc).
* The day names are sorted in date order, starting with Sunday.
* `group by function task.due.moment ? ( task.due.moment.day() === 0 ? task.due.format("[%%][8][%%]dddd") : task.due.format("[%%]d[%%]dddd") ) : "Undated"`
* Group by day of the week (Monday, Tuesday, etc).
* The day names are sorted in date order, starting with Monday.
* Tasks without due dates are displayed at the end, under a heading "Undated".
* This is best understood by pasting it in to a Tasks block in Obsidian and then deleting parts of the expression.
* The key technique is to say that if the day is Sunday (`0`), then force it to be displayed as date number `8`, so it comes after the other days of the week.
* `group by function (!task.due.moment) ? '%%4%% Undated' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% Overdue' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% Today' : '%%3%% Future'`
* Group task due dates in to 4 broad categories: `Overdue`, `Today`, `Future` and `Undated`, displayed in that order.
* Try this on a line before `group by due` if there are a lot of due date headings, and you would like them to be broken down in to some kind of structure.
* A limitation of Tasks expressions is that they each need to fit on a single line, so this uses nested ternary operators, making it powerful but very hard to read.
* In fact, for ease of development and testing, it was written in a full-fledged development environment as a series of if/else blocks, and then automatically refactored in these nested ternary operators.
* `group by function (!task.due.moment) ? '%%4%% ==Undated==' : result = task.due.moment.isBefore(moment(), 'day') ? '%%1%% ==Overdue==' : result = task.due.moment.isSame(moment(), 'day') ? '%%2%% ==Today==' : '%%3%% ==Future=='`
* As above, but the headings `Overdue`, `Today`, `Future` and `Undated` are highlighted.
* See the sample screenshot below.
![Tasks grouped by due date category, and then by due date](https://proxy-prod.omnivore-image-cache.app/600x0,siPKGht3mglkuseFvi45tMvJ_hZGufA4LlWk_Wo6L4M4/https://publish-01.obsidian.md/access/40e62a316a834ff6f495ebf1d122cae6/images/tasks_custom_groups_categorise_dates.png)
Sample image showing tasks grouped first by highlighted words `Overdue`, `Today`, `Future` and `Undated`, and then by individual due date.
### Done Date
* `group by done`
* The done date of the task, including the week-day, or `No done date`.
* `done` grouping option was introduced in Tasks 1.7.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by done date** is now possible.
* `group by function task.done.format("YYYY-MM-DD dddd")`
* Like "group by done", except it uses an empty string instead of "No done date" if there is no done date.
### Scheduled Date
* `group by scheduled`
* The scheduled date of the task, including the week-day, or `No scheduled date`.
* `scheduled` grouping option was introduced in Tasks 1.7.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by scheduled date** is now possible.
* `group by function task.scheduled.format("YYYY-MM-DD dddd")`
* Like "group by scheduled", except it uses an empty string instead of "No scheduled date" if there is no scheduled date.
### Start Date
* `group by start`
* The start date of the task, including the week-day, or `No start date`.
* `start` grouping option was introduced in Tasks 1.7.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by start date** is now possible.
* `group by function task.start.format("YYYY-MM-DD dddd")`
* Like "group by start", except it uses an empty string instead of "No start date" if there is no start date.
* `group by created`
* The created date of the task, including the week-day, or `No created date`.
`created` grouping option was introduced in Tasks 2.0.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by created date** is now possible.
* `group by function task.created.format("YYYY-MM-DD dddd")`
* Like "group by created", except it uses an empty string instead of "No created date" if there is no created date.
### Happens
* `group by happens`
* The earliest of start date, scheduled date, and due date, including the week-day, or `No happens date` if none of those are set.
`happens` grouping option was introduced in Tasks 1.11.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by happens date** is now possible.
* `group by function task.happens.format("YYYY-MM-DD dddd")`
* Like "group by happens", except it uses an empty string instead of "No happens date" if there is no happens date.
## Group by Other Task Properties
As well as the date-related groups above, groups can be created from properties in individual tasks.
### Description
There is no built-in instruction to group by description.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by description** is now possible.
* `group by function task.description`
* group by description.
* This might be useful for finding completed recurrences of the same task.
* `group by function task.description.toUpperCase()`
* Convert the description to capitals.
* `group by function task.description.slice(0, 25)`
* Truncate descriptions to at most their first 25 characters, and group by that string.
* `group by function task.description.replace('short', '==short==')`
* Highlight the word "short" in any group descriptions.
### Description without tags
Since Tasks 4.2.0, it is possible to remove tags from the descriptions in custom groups, for use in **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping)**.
The value `task.descriptionWithoutTags` returns a copy of the description with all the tags removed, so that you can group together any tasks whose descriptions differ only by their tags.
* `group by function task.descriptionWithoutTags`
* Like `group by description`, but it removes any tags from the group headings.
* This might be useful for finding completed recurrences of the same task, even if the tags differ in some recurrences.
### Priority
* `group by priority`
* The priority of the task, namely one of:
* `Highest priority`
* `High priority`
* `Medium priority`
* `Normal priority`
* `Low priority`
* `Lowest priority`
* `priority` grouping option was introduced in Tasks 1.11.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by priority name and number** is now possible.
Using the priority name:
* `group by function task.priorityName`
* Group by the task's priority name.
* The priority names are displayed in alphabetical order.
* Note that the default priority is called 'Normal', as opposed to with `group by priority` which calls the default 'None'.
* `group by function '%%' + task.priorityNumber.toString() + '%%' + task.priorityName +' priority'`
* Group by the task's priority name.
* The hidden priority number ensures that the headings are written from highest to lowest priority.
* Note that the default priority is called 'Normal', as opposed to with `group by priority` which calls the default 'None'.
Using the priority number:
* `group by function task.priorityNumber`
* Group by the task's priority number, where Highest is 0 and Lowest is 5.
### Urgency
* `group by urgency` ([urgency](https://publish.obsidian.md/tasks/Advanced/Urgency))
* The groups run from the highest urgency to the lowest.
* You can reverse this with `group by urgency reverse`.
* `urgency` grouping option was introduced in Tasks 3.6.0.
* In Tasks 4.0.0 the order of `group by urgency` was reversed, to put most urgent tasks first. Add or remove the word `reverse` to get the original order.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by urgency** is now possible.
* `group by function task.urgency.toFixed(3)`
* Show the urgency to 3 decimal places, unlike the built-in "group by urgency" which uses 2.
### Recurrence
* `group by recurring`
* Whether the task is recurring: either `Recurring` or `Not Recurring`.
* `group by recurrence`
* The recurrence rule of the task, for example `every week on Sunday`, or `None` for non-recurring tasks.
* Note that the text displayed is generated programmatically and standardised, and so may not exactly match the text in any manually typed tasks. For example, a task with `🔁 every Sunday` is grouped in `every week on Sunday`.
* `recurring` and `recurrence` grouping options were introduced in Tasks 1.11.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by recurrence** is now possible.
* `group by function task.isRecurring ? "Recurring" : "Non-Recurring"`
* Use JavaScript's ternary operator to choose what to do for true (after the ?) and false (after the :) values.
* `group by function task.recurrenceRule.replace('when done', '==when done==')`
* Group by recurrence rule, highlighting any occurrences of the words "when done".
### Tags
* `group by tags`
* The tags of the tasks or `(No tags)`. If the task has multiple tags, it will show up under every tag.
* `tags` grouping option was introduced in Tasks 1.10.0.
* `group by function task.tags`
* Like "group by tags" except that tasks with no tags have no heading instead of "(No tags)".
* `group by function task.tags.join(", ")`
* Tasks with multiple tags are listed once, with a heading that combines all the tags.
* Separating with commas means the tags are clickable in the headings.
* `group by function task.tags.sort().join(", ")`
* As above, but sorting the tags first ensures that the final headings are independent of order of tags in the tasks.
* `group by function task.tags.filter( (tag) => tag.includes("#context/") )`
* Only create headings for tags that contain "#context/".
* `group by function task.tags.filter( (tag) => ! tag.includes("#tag") )`
* Create headings for all tags that do not contain "#tag".
These are more complicated examples, which you might like to copy if you use tasks with [nested tags](https://help.obsidian.md/Editing+and+formatting/Tags#Nested+tags) and wish to group them at different tag nesting levels.
* `group by function task.tags.map( (tag) => tag.split('/')[0].replace('#', '') )`
* `#tag/subtag/sub-sub-tag` gives **`tag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(1, 2) : '')`
* `#tag/subtag/sub-sub-tag` gives **`subtag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(2, 3) : '')`
* `#tag/subtag/sub-sub-tag` gives **`sub-sub-tag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(3, 4) : '')`
* `#tag/subtag/sub-sub-tag` gives no heading, as there is no value at the 4th level.
* `group by function task.tags.map( (tag) => tag.split('/')[0] )`
* `#tag/subtag/sub-sub-tag` gives **`#tag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[1] ? tag.split('/').slice(0, 2).join('/') : '')`
* `#tag/subtag/sub-sub-tag` gives **`#tag/subtag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[2] ? tag.split('/').slice(0, 3).join('/') : '')`
* `#tag/subtag/sub-sub-tag` gives **`#tag/subtag/sub-sub-tag`**.
* `group by function task.tags.map( (tag) => tag.split('/')[3] ? tag.split('/').slice(0, 4).join('/') : '')`
* `#tag/subtag/sub-sub-tag` gives no heading, as there is no value at the 4th level.
### Original Markdown
There is no built-in instruction to group by the original markdown line.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by original markdown line** is now possible.
For example, this could be used to extract information from `task.originalMarkdown` that Tasks does not parse, to use for grouping tasks.
* ``` group by function '``' + task.originalMarkdown + '``' ```
* Group by the raw text of the task's original line in the MarkDown file as code.
* Note the pairs of backtick characters ('\`'), to preserve even single backtick characters in the task line.
* It's important to prevent the task checkbox (for example, '\[ \]') from being rendered in the heading, as it gets very confusing if there are checkboxes on both headings and tasks.
* `group by function task.originalMarkdown.replace(/^[^\[\]]+\[.\] */, '')`
* An alternative to formatting the markdown line as code is to remove everything up to the end of the checkbox.
* Then render the rest of the task line as normal markdown.
## Group by File Properties
### File Path
* `group by path` (the path to the file that contains the task, that is, the folder and the filename)
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by file path** is now possible.
* `group by function task.file.path`
* Like 'group by path' but includes the file extension.
### Root
* `group by root` (the top-level folder of the file that contains the task, that is, the first directory in the path, which will be `/` for files in root of the vault)
`root` grouping option was introduced in Tasks 1.11.0.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by root folder** is now possible.
* `group by function task.file.root`
* Same as 'group by root'.
### Folder
* `group by folder` (the folder to the file that contains the task, which always ends in `/` and will be exactly `/` for files in root of the vault)
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by folder** is now possible.
* `group by function task.file.folder`
* Same as 'group by folder'.
* `group by function task.file.folder.slice(0, -1).split('/').pop() + '/'`
* Group by the immediate parent folder of the file containing task.
* Here's how it works:
* '.slice(0, -1)' removes the trailing slash ('/') from the original folder.
* '.split('/')' divides the remaining path up in to an array of folder names.
* '.pop()' returns the last folder name, that is, the parent of the file containing the task.
* Then the trailing slash is added back, to ensure we do not get an empty string for files in the top level of the vault.
### File Name
* `group by filename` (the link to the file that contains the task, without the `.md` extension)
* Note that tasks from different notes with the same file name will be grouped together in the same group.
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by file name** is now possible.
* `group by function task.file.filename`
* Like 'group by filename' but does not link to the file.
* `group by function '[[' + task.file.filename.replace('.md', '') + ( task.hasHeading ? ('#' + task.heading) : '') + ']]'`
* Like 'group by backlink' but links to the heading in the file.
### Backlink
* `group by backlink` (the text that would be shown in the task's [backlink](https://publish.obsidian.md/tasks/Queries/Backlinks), combining the task's file name and heading, but with no link added)
### Heading
* `group by heading` (the heading preceding the task, or `(No heading)` if there are no headings in the file)
Since Tasks 4.0.0, **[custom grouping](https://publish.obsidian.md/tasks/Scripting/Custom+Grouping) by heading** is now possible.
* `group by function (task.heading + '.md' === task.file.filename) ? '' : task.heading`
* Group by heading, but only if the heading differs from the file name.
* This works well immediately after a 'group by filename' line.
* Note the three equals signs '===': these are important for safety in JavaScript.
## Multiple groups
You can add multiple `group by` query options, each on an extra line. This will create nested groups. The first group has the highest priority.
Each subsequent `group by` will generate a new heading-level within the existing grouping:
* First `group by` is displayed as `h4` headings
* Second `group by` is displayed as `h5` headings
* Third and subsequent `group by` are displayed as `h6` headings
Headings are displayed in case-sensitive alphabetical order, not the original order.
## Refining groups
### Reversing groups
Reversing of group headings was introduced in Tasks 3.7.0.
After the name of the property that you want to group by, you can add the `reverse` keyword. If given, the group headings will be reversed for that property.
For example:
* `group by due` will sort the group headings:
* from **oldest** due date first...
* to **newest** due date last
* `group by due reverse` will sort the group headings:
* from **newest** due date first...
* to **oldest** due date last
The `reverse` keyword controls the order that group headings are displayed.
The [sort by](https://publish.obsidian.md/tasks/Queries/Sorting) facility, by contrast, controls the order in which displays are displayed _inside_ each group.
### Limiting group size
You can limit the number of tasks in each group, perhaps to work on the most important things first.
## Notes
The order of operations ensures that grouping does not modify which tasks are displayed, for example when the `limit` options are used:
1. all the filter instructions are run
2. then any sorting instructions are run
3. then any `limit` instructions are run
4. then any grouping instructions are run
5. then any `limit groups` instructions are run
## Screenshots
### Before
Here is an example Tasks result, without any `group by` commands:
![Tasks Ungrouped](https://proxy-prod.omnivore-image-cache.app/0x0,sSjXUpAFImYOXi0dbzLz2Y9ARB0qM_TlDAVdfIFSbwTw/https://publish-01.obsidian.md/access/40e62a316a834ff6f495ebf1d122cae6/images/tasks_ungrouped.png)
Tasks not grouped.
### After
And here is what this might look like, when grouped by folder, filename and heading:
![Tasks Grouped](https://proxy-prod.omnivore-image-cache.app/0x0,s4L0CpwKfD_GP_wuUO65IooyumqPfjG2hor7hPbPcUdE/https://publish-01.obsidian.md/access/40e62a316a834ff6f495ebf1d122cae6/images/tasks_grouped.png)
Tasks grouped.
## Examples
Give me three levels of grouping, to indicate the locations of my tasks:
```routeros
```tasks
not done
group by folder
group by filename
group by heading
```
```
Show me tasks I need to do today - and put today's tasks first, for visibility:
```routeros
```tasks
not done
due before tomorrow
group by due reverse
```
```
Grouping