Skip to content

14. Late Data: Incremental with a Lookback

Difficulty: Hard · Topic: Incremental models

daily_page_views aggregates {{ source('web', 'page_views') }} to one row per day: view_date (the date of viewed_at), views (count) and users (distinct user_id).

Mobile apps upload views late, up to two days after they happened, so the newest days in the table are often incomplete. Make it incremental so that each run recomputes, from the source, every day from 2 days before the latest view_date already in the table onwards, replacing those days. Older days are final and are not touched.

Example: if the table's latest day is 10 June, the run recomputes 8 June, 9 June, 10 June and anything newer.

Your model is compiled like dbt does and run in DuckDB against 3 test cases, including hidden edge cases.

Sample inputs

{{ source('web', 'page_views') }}

view_iduser_idviewed_at
112024-06-07 10:00:00
212024-06-07 11:00:00
322024-06-07 12:00:00
412024-06-08 09:00:00
532024-06-08 10:00:00
622024-06-09 08:00:00
742024-06-09 23:00:00
812024-06-10 07:00:00
952024-06-10 13:00:00
1052024-06-11 01:00:00
1162024-06-06 22:00:00

The table before the run

view_dateviewsusers
2024-06-0732
2024-06-0822
2024-06-0911
2024-06-1011

Expected output

view_dateviewsusers
2024-06-0732
2024-06-0822
2024-06-0922
2024-06-1022
2024-06-1111

Hints

Hint 1The grain is a day, so the unique key is view_date: recomputed days replace the old rows for those days.
Hint 2Filter on whole days, not timestamps: where cast(viewed_at as date) >= (select max(view_date) from {{ this }}) - interval 2 day. A filter on the newest timestamp would recompute a day from only part of its rows.
Hint 3Older days must stay as they are, even if late rows for them show up now: that is the price of a fixed lookback window.

More dbt problems

All dbt problems