mdbplyr

A native tidy lazy backend for MongoDB in R.

Overview

mdbplyr provides a disciplined dplyr-style interface for read-only analytical MongoDB queries. Queries stay lazy, compile into MongoDB aggregation pipelines, and only execute at collect().

The package is intentionally conservative:

Install

You can install the package from CRAN with install.package("mdbplyr"). If you rather want the latest version from GitHub:

install.package(c("devtools", "remotes", "knitr", "rmarkdown"))
remotes::install_github("pbosetti/mdbplyr", build_vignettes = TRUE)

Current implemented subset

Core objects and terminals

Supported verbs

Supported expressions

Current limits

Example

library(mdbplyr)
library(dplyr)

orders <- tbl_mongo(
  collection = mongolite::mongo(collection = "orders", db = "analytics"),
  schema = c("customer", "amount", "status")
)

query <- orders |>
  filter(status == "paid", amount > 0) |>
  mutate(double_amount = amount * 2) |>
  group_by(customer) |>
  summarise(total = sum(double_amount), n = n()) |>
  arrange(desc(total)) |>
  slice_head(n = 10)

show_query(query)
result <- collect(query)

iter <- cursor(query)
first_page <- iter$page(5)

When field metadata is not discoverable from the collection object, pass schema = ... to tbl_mongo() so that projection and rename operations can stay explicit and lazy.


Design Position

The package provides:

This project should be framed as:

a native tidy lazy analytical backend for MongoDB.

It should not be framed as:

a complete dbplyr equivalent for MongoDB.

MongoDB documents are not rectangular SQL tables. Nested fields, arrays, missing keys, heterogeneous schemas, and document-oriented semantics require a backend that is native to MongoDB rather than adapted from SQL assumptions.

For these reasons, the package can not aim to deliver full dplyr compatibility over arbitrary MongoDB collections.


Support matrix

Capability Status Notes
Lazy query state Supported Verbs update internal IR only
Pipeline inspection Supported show_query() renders compiled JSON
Flat-field filters Supported Uses $match + $expr
Projection and rename Supported with caveats select() adds name-based tidyselect helpers (no where()); rename() is bare renames
Scalar mutation Supported Conservative expression subset
Grouped summaries Supported n(), sum(), mean(), min(), max(), sd(), var(), first(), last(), n_distinct(); median()/quantile() need MongoDB 7.0+
Computed group keys Supported Named expressions, e.g. group_by(bucket = floor(amount / 10))
across() Supported with caveats Name-based selections; bare function names or ~ lambdas; no where() or function variables
Dot-path fields Supported with caveats Use backticked names such as `user.age`
Manual pipeline stage append Supported with caveats append_stage() appends raw JSON after generated stages and does not infer schema changes
Window functions Supported with caveats $setWindowFields (MongoDB 5.0+); rank/dense_rank, cum*, lag/lead; ordering via the ranking column or a preceding arrange()
Joins Supported with caveats inner/left/semi/anti via $lookup; plain right-hand tbl_mongo, same database; flattened by default or nested with unnest = FALSE
Reshaping / writes Not supported Explicitly out of scope
Client-side fallback Not supported Unsupported features error clearly

Core Technical Principles

1. Native MongoDB translation

Do not generate SQL. Do not emulate SQL. Translate directly into MongoDB aggregation pipelines.

2. Internal intermediate representation

Introduce a package-specific internal query representation between the user API and the pipeline compiler.

This is a core design requirement. It allows:

3. Lazy semantics

All supported verbs should update query state, not execute immediately.

Execution should occur only at terminal steps such as collect().

4. Explicit failure

Unsupported operations should fail with precise diagnostics. The package should not silently pull data locally and continue computation unless that behavior is deliberately introduced later as an opt-in mode.

5. Conservative semantics

Ambiguous cases should be handled conservatively and documented explicitly, especially for:


Expected Translation Model

Typical verb mappings are:

This mapping should be documented, inspectable, and testable.


Author

Paolo Bosetti, University of Trento, Department of Industrial Engineering https://ror.org/05trd4x28