← Blog
Architecture9 minMay 28, 2026

Designing RBAC with sub-ms access checks on MongoDB

Sparse indexes, role hierarchies, and keeping authorization off the hot path in a multi-owner CRM.

The access control problem

Meraki had three roles per lead: primary owner, co-assignee, and opportunity owner. Any of these could read the lead. Only the primary owner could reassign it. Managers could see all leads in their team. Admins could see everything.

The naive implementation — fetch the lead, then check role in application code — puts authorization on the hot path and requires a second round-trip. At 50K+ leads and 100+ concurrent reps, that is too slow.

Sparse indexes on MongoDB

The trick is to encode authorization into the query itself. Instead of fetching and filtering, we store the authorized user IDs directly on the document and query against them.

// Document structure
{
  _id: ObjectId,
  title: String,
  primaryOwner: ObjectId,
  coAssignees: [ObjectId],
  opportunityOwner: ObjectId,
  teamId: ObjectId
}

// Sparse index — only indexes documents where the field exists
db.leads.createIndex({ primaryOwner: 1 }, { sparse: true })
db.leads.createIndex({ coAssignees: 1 }, { sparse: true })
db.leads.createIndex({ teamId: 1 }, { sparse: true })

The query

A rep querying their leads gets a single query that matches any of their authorized roles. MongoDB evaluates this against the indexes directly — no application-level filtering needed.

db.leads.find({
  : [
    { primaryOwner: userId },
    { coAssignees: userId },
    { opportunityOwner: userId },
    { teamId: { : userTeamIds } }  // manager access
  ]
})

Sub-millisecond access checks

With sparse indexes on each role field, MongoDB can resolve the branches against indexes and return results without a collection scan. For a typical rep with access to ~200 leads out of 50K+, this resolves in under 1ms.

The assignment service

Reassignment needed to be idempotent. Two managers clicking "reassign" at the same time should not corrupt the ownership state. We used a single-writer service with optimistic concurrency — each document has a version field, and the update only succeeds if the version matches.

result = db.leads.update_one(
    {"_id": lead_id, "_version": current_version},
    {
        "": {"primaryOwner": new_owner, "updatedAt": datetime.utcnow()},
        "": {"_version": 1}
    }
)
if result.modified_count == 0:
    raise ConcurrentModificationError()
Designing RBAC with sub-ms access checks on MongoDB — Ayush Chaudhari