Introduction
wpgdata provides a tidy R interface to the City of Winnipeg Open Data Portal.
Discover available datasets, inspect their schemas, and download records
with automatic parallel pagination — all via the Socrata OData V4 and
Discovery APIs.
This vignette walks through the four core functions using the
Assessment Parcels dataset (d4mq-wa44) as the primary
working example, with additional examples using the 311 Service Requests
dataset (u7f6-5326) to demonstrate date filtering on large
datasets.
Workflow overview
The typical wpgdata workflow follows four steps:
| Function | Purpose |
|---|---|
peg_catalogue() |
Browse all available datasets and find IDs |
peg_info() |
Explore a specific dataset |
peg_metadata() |
Find field names before querying |
peg_data() |
Filter, select, sort, and download rows |
Step 1 — Find datasets with peg_catalogue()
peg_catalogue() retrieves every published dataset from
the portal. Both catalogue pages and per-dataset metadata are fetched in
parallel, so the full catalogue arrives quickly regardless of size.
catalogue <- peg_catalogue()
catalogue
#> # A tibble: 217 × 22
#> id name description category license_id created_at rows_updated_at
#> <chr> <chr> <chr> <chr> <chr> <date> <date>
#> 1 d4mq-wa44 Assessm… "List of a… Assessm… OGL_CANADA 2017-08-23 2026-03-20
#> 2 yg42-q284 WFPS Ca… "The data … Fire an… OGL_CANADA 2020-12-14 2026-03-20
#> 3 iibp-28fx Burial … "Locations… Cemeter… OGL_CANADA 2016-01-29 2026-03-20
#> 4 vrzk-mj7v 311 Cal… "Caller wa… Contact… OGL_CANADA 2022-06-17 2026-03-20
#> 5 gnxp-9hpt Public … "Public No… Develop… NA 2016-08-08 2026-03-20
#> 6 tix9-r5tc Plow Zo… "Scheduled… City Pl… NA 2016-10-18 2026-03-20
#> 7 8xrn-n992 Capital… "The Capit… Assessm… NA 2015-12-01 2026-03-20
#> 8 du7c-8488 Daily A… "The data … Insect … NA 2016-05-04 2026-03-20
#> 9 pfbi-rm6v FIPPA R… "The Freed… Organiz… OGL_CANADA 2019-09-10 2026-03-20
#> 10 tgrf-v2zc River W… "Record of… Water a… OGL_CANADA 2018-03-15 2026-03-20
#> # ℹ 207 more rows
#> # ℹ 15 more variables: view_last_modified <date>, publication_date <date>,
#> # index_updated_at <date>, row_count <int>, col_count <int>,
#> # download_count <int>, view_count <int>, group <chr>, department <chr>,
#> # update_frequency <chr>, quality_rank <chr>, license <chr>,
#> # license_link <chr>, tags <list>, url <chr>Count datasets by category to get an overview of what’s available:
catalogue |>
count(category, sort = TRUE)
#> # A tibble: 26 × 2
#> category n
#> <chr> <int>
#> 1 Census 35
#> 2 City Planning 27
#> 3 Development Approvals, Building Permits, & Inspections 24
#> 4 Transportation Planning & Traffic Management 18
#> 5 Uncategorized 16
#> 6 Council Services 15
#> 7 Recreation 9
#> 8 Organizational Support Services 8
#> 9 Assessment, Taxation, & Corporate 7
#> 10 Contact Centre - 311 7
#> # ℹ 16 more rowsSearch by name to find a dataset and retrieve its ID:
catalogue |>
filter(grepl("assessment", name, ignore.case = TRUE)) |>
select(name, id, rows_updated_at)
#> # A tibble: 1 × 3
#> name id rows_updated_at
#> <chr> <chr> <date>
#> 1 Assessment Parcels d4mq-wa44 2026-03-20Use the id value in any other peg_*
function:
dataset_id <- catalogue |>
filter(name == "Assessment Parcels") |>
pull(id)
dataset_id
#> [1] "d4mq-wa44"Use limit to cap results while exploring:
peg_catalogue(limit = 10)
#> # A tibble: 10 × 22
#> id name description category license_id created_at rows_updated_at
#> <chr> <chr> <chr> <chr> <chr> <date> <date>
#> 1 d4mq-wa44 Assessm… "List of a… Assessm… OGL_CANADA 2017-08-23 2026-03-20
#> 2 yg42-q284 WFPS Ca… "The data … Fire an… OGL_CANADA 2020-12-14 2026-03-20
#> 3 iibp-28fx Burial … "Locations… Cemeter… OGL_CANADA 2016-01-29 2026-03-20
#> 4 vrzk-mj7v 311 Cal… "Caller wa… Contact… OGL_CANADA 2022-06-17 2026-03-20
#> 5 gnxp-9hpt Public … "Public No… Develop… NA 2016-08-08 2026-03-20
#> 6 6rcy-9uik Recycli… "Collectio… Water a… OGL_CANADA 2017-09-08 2026-03-16
#> 7 hfwk-jp4h Tree In… "Detailed … Parks OGL_CANADA 2017-08-22 2026-03-16
#> 8 p5sy-gt7y Aggrega… "Aggregate… Develop… NA 2016-12-21 2026-03-16
#> 9 it4w-cpf4 Detaile… "City of W… Develop… NA 2016-04-18 2026-03-01
#> 10 4her-3th5 311 Ser… "This data… Contact… NA 2015-07-22 2025-04-15
#> # ℹ 15 more variables: view_last_modified <date>, publication_date <date>,
#> # index_updated_at <date>, row_count <int>, col_count <int>,
#> # download_count <int>, view_count <int>, group <chr>, department <chr>,
#> # update_frequency <chr>, quality_rank <chr>, license <chr>,
#> # license_link <chr>, tags <list>, url <chr>Step 2 — Explore a dataset with peg_info()
peg_info() returns high-level metadata for a single
dataset — name, description, category, update frequency, row count, and
license:
peg_info("d4mq-wa44")
#> # A tibble: 1 × 11
#> name description category created_at rows_updated_at view_last_modified
#> <chr> <chr> <chr> <date> <date> <date>
#> 1 Assessment… List of al… Assessm… 2017-08-23 2026-03-20 2026-03-20
#> # ℹ 5 more variables: view_count <int>, download_count <int>, tags <list>,
#> # license <chr>, provenance <chr>This is useful before committing to a large download: it tells you when the data was last updated, how many rows to expect, and what license it is published under.
Step 3 — Find field names with peg_metadata()
OData queries require exact field names. Use
peg_metadata() to look up available fields and their types
before writing any query:
meta <- peg_metadata("d4mq-wa44")
meta
#> # A tibble: 71 × 4
#> name field_name type description
#> <chr> <chr> <chr> <chr>
#> 1 Roll Number roll_number text NA
#> 2 Street Number street_number number NA
#> 3 Unit Number unit_number text NA
#> 4 Street Suffix street_suffix text NA
#> 5 Street Direction street_direction text NA
#> 6 Street Name street_name text NA
#> 7 Street Type street_type text NA
#> 8 Full Address full_address text NA
#> 9 Neighbourhood Area neighbourhood_area text NA
#> 10 Market Region market_region text NA
#> # ℹ 61 more rowsThe field_name column contains the names to use in
peg_data(). The type column tells you whether
a field is text, number, floating timestamp, or another type — important
for writing correct filter expressions.
Find numeric fields only:
meta |>
filter(type == "number")
#> # A tibble: 24 × 4
#> name field_name type description
#> <chr> <chr> <chr> <chr>
#> 1 Street Number street_number numb… NA
#> 2 Total Living Area total_living_area numb… In Square …
#> 3 Year Built year_built numb… NA
#> 4 Rooms rooms numb… NA
#> 5 Number Floors (Condo) number_floors_condo numb… NA
#> 6 Assessed Land Area assessed_land_area numb… In Square …
#> 7 Water Frontage Measurement water_frontage_measurement numb… in Feet
#> 8 Sewer Frontage Measurement sewer_frontage_measurement numb… In Feet
#> 9 Total Assessed Value total_assessed_value numb… NA
#> 10 Total Proposed Assessment Value total_proposed_assessment_… numb… NA
#> # ℹ 14 more rowsFind timestamp fields (relevant for date filtering):
meta |>
filter(type == "calendar_date")
#> # A tibble: 2 × 4
#> name field_name type description
#> <chr> <chr> <chr> <chr>
#> 1 Assessment Date assessment_date calendar_date ""
#> 2 Proposed Assessment Date proposed_assessment_date calendar_date NAStep 4 — Fetch data with peg_data()
peg_data() is the single function for fetching rows. It
supports server-side filtering, column selection, sorting, and offset
pagination. All pages are fetched in parallel automatically — no manual
pagination needed.
Quick preview
Fetch a small sample to inspect structure before a larger query:
peg_data("d4mq-wa44", top = 5)
#> # A tibble: 5 × 72
#> `__id` roll_number street_number unit_number street_suffix street_direction
#> <chr> <chr> <int> <chr> <lgl> <lgl>
#> 1 row-fhe3… 01000001000 1636 NA NA NA
#> 2 row-b7ye… 01000005500 1584 NA NA NA
#> 3 row-8en9… 01000008000 1574 NA NA NA
#> 4 row-8e6t… 01000008200 1550 NA NA NA
#> 5 row-8j4b… 01000008400 1538 NA NA NA
#> # ℹ 66 more variables: street_name <chr>, street_type <chr>,
#> # full_address <chr>, neighbourhood_area <chr>, market_region <chr>,
#> # total_living_area <int>, building_type <chr>, basement <chr>,
#> # basement_finish <chr>, year_built <int>, rooms <int>,
#> # air_conditioning <chr>, fire_place <chr>, attached_garage <chr>,
#> # detached_garage <chr>, pool <chr>, number_floors_condo <int>,
#> # property_use_code <chr>, assessed_land_area <int>, …Filtering rows
Pass R expressions directly — wpgdata translates them to
OData syntax:
peg_data("d4mq-wa44",
filter = total_assessed_value > 1000000,
top = 10
)
#> # A tibble: 10 × 72
#> `__id` roll_number street_number unit_number street_suffix street_direction
#> <chr> <chr> <int> <chr> <chr> <chr>
#> 1 row-b7y… 01000005500 1584 NA NA NA
#> 2 row-5zx… 01000013200 1520 NA NA NA
#> 3 row-knr… 01000014500 1450 NA NA NA
#> 4 row-vpp… 01000045500 1290 NA NA NA
#> 5 row-8j8… 01000064000 1820 NA NA NA
#> 6 row-mst… 01000067500 1916 NA NA NA
#> 7 row-wq5… 01000067900 1892 NA NA NA
#> 8 row-hfi… 01000092200 1700 NA NA NA
#> 9 row-9rr… 01000096000 1720 NA NA NA
#> 10 row-e9m… 01000306500 2424 NA NA NA
#> # ℹ 66 more variables: street_name <chr>, street_type <chr>,
#> # full_address <chr>, neighbourhood_area <chr>, market_region <chr>,
#> # total_living_area <int>, building_type <chr>, basement <chr>,
#> # basement_finish <chr>, year_built <int>, rooms <int>,
#> # air_conditioning <chr>, fire_place <chr>, attached_garage <chr>,
#> # detached_garage <chr>, pool <chr>, number_floors_condo <lgl>,
#> # property_use_code <chr>, assessed_land_area <int>, …Or use raw OData strings if you prefer:
peg_data("d4mq-wa44",
filter = "total_assessed_value gt 1000000",
top = 10
)
#> # A tibble: 10 × 72
#> `__id` roll_number street_number unit_number street_suffix street_direction
#> <chr> <chr> <int> <chr> <chr> <chr>
#> 1 row-b7y… 01000005500 1584 NA NA NA
#> 2 row-5zx… 01000013200 1520 NA NA NA
#> 3 row-knr… 01000014500 1450 NA NA NA
#> 4 row-vpp… 01000045500 1290 NA NA NA
#> 5 row-8j8… 01000064000 1820 NA NA NA
#> 6 row-mst… 01000067500 1916 NA NA NA
#> 7 row-wq5… 01000067900 1892 NA NA NA
#> 8 row-hfi… 01000092200 1700 NA NA NA
#> 9 row-9rr… 01000096000 1720 NA NA NA
#> 10 row-e9m… 01000306500 2424 NA NA NA
#> # ℹ 66 more variables: street_name <chr>, street_type <chr>,
#> # full_address <chr>, neighbourhood_area <chr>, market_region <chr>,
#> # total_living_area <int>, building_type <chr>, basement <chr>,
#> # basement_finish <chr>, year_built <int>, rooms <int>,
#> # air_conditioning <chr>, fire_place <chr>, attached_garage <chr>,
#> # detached_garage <chr>, pool <chr>, number_floors_condo <lgl>,
#> # property_use_code <chr>, assessed_land_area <int>, …Both approaches produce identical results.
Compound filters
Combine conditions with & (AND) and |
(OR):
peg_data("d4mq-wa44",
filter = total_assessed_value > 1000000 & building_type == "TWO STOREY",
top = 10
)
#> # A tibble: 10 × 72
#> `__id` roll_number street_number unit_number street_suffix street_direction
#> <chr> <chr> <int> <chr> <lgl> <chr>
#> 1 row-b7y… 01000005500 1584 NA NA NA
#> 2 row-5zx… 01000013200 1520 NA NA NA
#> 3 row-knr… 01000014500 1450 NA NA NA
#> 4 row-8j8… 01000064000 1820 NA NA NA
#> 5 row-md5… 01000560000 3179 NA NA NA
#> 6 row-x5m… 01000615000 3 NA NA NA
#> 7 row-hrh… 01000615400 17 NA NA NA
#> 8 row-2x2… 01000615800 31 NA NA NA
#> 9 row-h9d… 01000617400 36 NA NA NA
#> 10 row-fbt… 01000718800 400 NA NA NA
#> # ℹ 66 more variables: street_name <chr>, street_type <chr>,
#> # full_address <chr>, neighbourhood_area <chr>, market_region <chr>,
#> # total_living_area <int>, building_type <chr>, basement <chr>,
#> # basement_finish <chr>, year_built <int>, rooms <int>,
#> # air_conditioning <chr>, fire_place <chr>, attached_garage <chr>,
#> # detached_garage <chr>, pool <chr>, number_floors_condo <lgl>,
#> # property_use_code <chr>, assessed_land_area <int>, …Selecting columns
Use select to return only the columns you need — reduces
transfer size significantly on wide datasets:
peg_data("d4mq-wa44",
select = c("roll_number", "full_address", "total_assessed_value",
"building_type", "year_built"),
top = 10
)
#> # A tibble: 10 × 5
#> roll_number full_address building_type year_built total_assessed_value
#> <chr> <chr> <chr> <int> <int>
#> 1 01000001000 1636 MCCREARY ROAD ONE STOREY 1991 723000
#> 2 01000005500 1584 MCCREARY ROAD TWO STOREY 1991 1619000
#> 3 01000008000 1574 MCCREARY ROAD ONE STOREY 2007 570000
#> 4 01000008200 1550 MCCREARY ROAD ONE STOREY 1982 743000
#> 5 01000008400 1538 MCCREARY ROAD ONE STOREY 1970 577000
#> 6 01000008500 1536 MCCREARY ROAD 4 LEVEL SPLIT 1958 979000
#> 7 01000013200 1520 MCCREARY ROAD TWO STOREY 2021 1900000
#> 8 01000013300 1510 MCCREARY ROAD ONE & 1/2 STO… 2000 995000
#> 9 01000013600 1500 MCCREARY ROAD ONE & 1/2 STO… 1994 669000
#> 10 01000013700 1490 MCCREARY ROAD CABOVER 2008 882000Sorting results
Use orderby to sort ascending or descending:
peg_data("d4mq-wa44",
select = c("roll_number", "full_address", "total_assessed_value"),
orderby = "total_assessed_value desc",
top = 10
)
#> # A tibble: 10 × 3
#> roll_number full_address total_assessed_value
#> <chr> <chr> <int>
#> 1 13099071230 1485 PORTAGE AVENUE 651316000
#> 2 03091643600 92 DYSART ROAD 475244000
#> 3 08020955700 1225 ST MARY'S ROAD 328848000
#> 4 13096152000 700 WILLIAM AVENUE 262782000
#> 5 12092819100 10 KENNEDY STREET 262044000
#> 6 12093468100 242 HARGRAVE STREET 214972000
#> 7 06072082500 409 TACHE AVENUE 206873000
#> 8 10006776045 555 STERLING LYON PARKWAY 200244000
#> 9 07055050000 T-35-2000 WELLINGTON AVENUE 180099000
#> 10 09010473150 1555 REGENT AVENUE W 162335000Combining filter, select, and orderby
peg_data("d4mq-wa44",
filter = total_assessed_value > 1000000 & year_built > 2000,
select = c("roll_number", "full_address", "total_assessed_value",
"building_type", "year_built"),
orderby = "total_assessed_value desc",
top = 10
)
#> # A tibble: 10 × 5
#> roll_number full_address building_type year_built total_assessed_value
#> <chr> <chr> <chr> <int> <int>
#> 1 10004062400 23 KERSLAKE PLACE TWO STOREY 2006 4235000
#> 2 10003003000 137 HANDSART BOULE… TWO STOREY 2006 4077000
#> 3 10002999100 214 GRENFELL BOULE… TWO STOREY 2009 4054000
#> 4 10006777080 36 AVONLYNN COURT ONE STOREY 2022 3905000
#> 5 12040844000 885 WELLINGTON CRE… TWO STOREY 2021 3855000
#> 6 10002760000 135 PARK BOULEVARD… TWO STOREY 2023 3643000
#> 7 01002770500 70 RIDGEDALE CRESC… TWO STOREY 2024 3486000
#> 8 10002884000 130 HANDSART BOULE… TWO STOREY 2020 3386000
#> 9 10006776560 124 GRENFELL BOULE… TWO STOREY 2017 3335000
#> 10 10003006000 123 HANDSART BOULE… TWO STOREY 2005 3304000Fetching all rows
Omit top to fetch every matching row across all
pages:
# fetches all rows — may take several minutes for large datasets
peg_data("d4mq-wa44")Date filtering
Datasets with timestamp columns (type calendar_date or
floating_timestamp in peg_metadata()) support
date range filters via raw OData strings. Socrata floating timestamps
use ISO 8601 format with milliseconds:
YYYY-MM-DDTHH:MM:SS.mmm.
Build cutoff strings with a small helper to avoid repeating the format:
# helper — format a Date as a Socrata floating timestamp string
ts <- function(date) format(date, "%Y-%m-%dT00:00:00.000")The examples below use the 311 Service Requests dataset
(u7f6-5326), which has 18+ million rows and is updated
continuously — date filters are essential to avoid downloading the
entire dataset.
Records closed in the last 4 days
filter_str <- paste0("closed_date ge '", ts(Sys.Date() - 4), "'")
peg_data(
"u7f6-5326",
filter = filter_str,
select = c("case_id", "channel_type", "subject", "reason",
"type", "open_date", "closed_date", "case_status",
"neighbourhood", "ward"),
top = 100L
)
#> # A tibble: 100 × 10
#> case_id channel_type subject reason type open_date closed_date case_status
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 00e17bc8… Voice In Servic… Water… Wate… 2014-09-… 2026-03-18… Closed
#> 2 0130e8c6… Voice In Servic… City … Indi… 2018-11-… 2026-03-17… Closed
#> 3 0145e387… Voice In Servic… Water… Wate… 2014-06-… 2026-03-18… Closed
#> 4 016c4370… Voice In Servic… Water… Wate… 2014-02-… 2026-03-18… Closed
#> 5 01d35870… Voice In Servic… Water… Wate… 2014-09-… 2026-03-18… Closed
#> 6 029fed7e… Voice In Servic… City … Indi… 2019-03-… 2026-03-17… Closed
#> 7 042218b5… Voice In Servic… Water… Valv… 2014-03-… 2026-03-18… Closed
#> 8 04d029f1… Voice In Servic… Water… Valv… 2014-05-… 2026-03-18… Closed
#> 9 05d0fc55… Voice In Servic… Plann… City… 2015-10-… 2026-03-17… Closed
#> 10 05d0fc55… Self Service Servic… Plann… City… 2015-10-… 2026-03-17… Closed
#> # ℹ 90 more rows
#> # ℹ 2 more variables: neighbourhood <chr>, ward <chr>Records closed within a specific date range
filter_str <- paste0(
"closed_date ge '", ts(as.Date("2026-03-01")), "'",
" and ",
"closed_date lt '", ts(as.Date("2026-03-07")), "'"
)
peg_data(
"u7f6-5326",
filter = filter_str,
select = c("case_id", "subject", "open_date", "closed_date", "case_status"),
top = 100L
)
#> # A tibble: 100 × 5
#> case_id subject open_date closed_date case_status
#> <chr> <chr> <chr> <chr> <chr>
#> 1 925ba9824f63b6e105eb00dc8f069b56e4… Servic… 2018-04-… 2026-03-06… Closed
#> 2 ef9eb1f31d08f9c23314e28c86c4cdc66a… Servic… 2023-02-… 2026-03-04… Closed
#> 3 e17ba4e93b31b085f5f102113833ecc3b8… Servic… 2023-06-… 2026-03-05… Closed
#> 4 e17ba4e93b31b085f5f102113833ecc3b8… Servic… 2023-06-… 2026-03-05… Closed
#> 5 c54dfa99aa65b99836b03401b63f7576f8… Servic… 2023-08-… 2026-03-04… Closed
#> 6 b6bd446227ce1aef7480f1aec1e60d97cc… Servic… 2023-09-… 2026-03-04… Closed
#> 7 d81f9c3026c55e7b9fd049c13cb825f03f… Servic… 2023-12-… 2026-03-06… Closed
#> 8 5b52f3b44ddc0fdaffe18f93c7529579b9… Servic… 2023-12-… 2026-03-06… Closed
#> 9 71c5dea21dbeba15537e1b26084bc6b908… Servic… 2023-12-… 2026-03-06… Closed
#> 10 c48b7cd13abf00d7de74c92cf918efc15b… Servic… 2023-12-… 2026-03-06… Closed
#> # ℹ 90 more rowsOpen cases from the last 7 days
filter_str <- paste0(
"open_date ge '", ts(Sys.Date() - 7), "'",
" and ",
"case_status eq 'Open'"
)
peg_data(
"u7f6-5326",
filter = filter_str,
select = c("case_id", "subject", "reason", "open_date",
"case_status", "neighbourhood", "ward"),
top = 100L
)
#> # A tibble: 100 × 7
#> case_id subject reason open_date case_status neighbourhood ward
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 85737cf8aed019baf1b… Servic… Asses… 2026-03-… Open NA NA
#> 2 a5f641c1fefc70ff811… Servic… Water… 2026-03-… Open King Edward St. …
#> 3 14413d52546953d2bf9… Servic… Water… 2026-03-… Open Pulberry St. …
#> 4 def3469b275f18e5096… Servic… Trans… 2026-03-… Open NA NA
#> 5 959b3538554dd6e8524… Servic… Asses… 2026-03-… Open River East Nort…
#> 6 0d00b3abc5db0f1caea… Servic… Publi… 2026-03-… Open NA NA
#> 7 0a8da3ffeea5d452f8a… Servic… Publi… 2026-03-… Open NA NA
#> 8 ba23f5972a6c8736651… Servic… Water… 2026-03-… Open NA NA
#> 9 62a617b57be61a7df4f… Servic… Water… 2026-03-… Open Holden St. …
#> 10 4e767e8dc87d00cb621… Servic… Water… 2026-03-… Open Silver Heigh… St. …
#> # ℹ 90 more rowsCases closed yesterday, sorted by most recently closed
filter_str <- paste0(
"closed_date ge '", ts(Sys.Date() - 1), "'",
" and ",
"closed_date lt '", ts(Sys.Date()), "'"
)
peg_data(
"u7f6-5326",
filter = filter_str,
select = c("case_id", "subject", "channel_type",
"open_date", "closed_date", "neighbourhood"),
orderby = "closed_date desc",
top = 100L
)
#> # A tibble: 7 × 6
#> case_id channel_type subject open_date closed_date neighbourhood
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 5290205807c2d82aa351… Voice In Servic… 2026-03-… 2026-03-19… Tyndall Park
#> 2 86dac5efdb20f2cec795… VOF Servic… 2026-03-… 2026-03-19… NA
#> 3 e904e530d8d53c6ad88b… Voice In Inform… 2026-03-… 2026-03-19… NA
#> 4 3887658d92e0ebd73e6d… Voice In Servic… 2026-03-… 2026-03-19… Munroe East
#> 5 6ced2002c49a11832772… Voice In Servic… 2026-03-… 2026-03-19… NA
#> 6 0be9a18a56d20852ff76… Voice In Servic… 2026-03-… 2026-03-19… NA
#> 7 cdbcadd803817f39dbe0… Voice In Inform… 2026-03-… 2026-03-19… NANote: The
topargument is included in all date filter examples to keep live API calls lightweight during development. Remove it to retrieve the full result set.
OData filter reference
| R expression | OData equivalent | Meaning |
|---|---|---|
x == 1 |
x eq 1 |
equal |
x != 1 |
x ne 1 |
not equal |
x > 1 |
x gt 1 |
greater than |
x >= 1 |
x ge 1 |
greater than or equal |
x < 1 |
x lt 1 |
less than |
x <= 1 |
x le 1 |
less than or equal |
x == 1 & y == 2 |
(x eq 1 and y eq 2) |
AND |
x == 1 \| y == 2 |
(x eq 1 or y eq 2) |
OR |
!x |
not x |
NOT |
Tip: R expression syntax works for numeric and string comparisons. For date comparisons, use raw OData strings as shown in the date filtering section above.
Finding dataset IDs
The easiest way is to search directly in R:
peg_catalogue() |>
filter(grepl("your search term", name, ignore.case = TRUE)) |>
select(name, id, category)Alternatively, browse the City of Winnipeg Open Data Portal, open any dataset, click API → OData V4, and copy the last segment of the URL:
https://data.winnipeg.ca/api/odata/v4/d4mq-wa44
^^^^^^^^^^
dataset ID
