Mongoose adapter
| This documentation is for an as-yet unreleased version of Cerbos. Choose 0.50.0 from the version picker at the top right or navigate to https://docs.cerbos.dev for the latest version. |
The @cerbos/orm-mongoose package converts a Cerbos PlanResources response into a MongoDB filter compatible with Mongoose’s find() method.
Requirements
-
Cerbos >= v0.16
-
@cerbos/httpor@cerbos/grpcclient -
Mongoose 8.x or 9.x
-
MongoDB 5.0+
-
Node.js >= 20.0.0
Supported operators
| Category | Operators |
|---|---|
Logical |
|
Comparison |
|
Membership |
|
String |
|
Existence |
|
Collection |
|
exists_one behaves as "at least one element matches". Enforcing "exactly one" requires an aggregation pipeline, which is outside the scope of this adapter.
|
Usage
import { queryPlanToMongoose, PlanKind } from "@cerbos/orm-mongoose";
const queryPlan = await cerbos.planResources({
principal: { id: "user1", roles: ["USER"] },
resource: { kind: "document" },
action: "view",
});
const result = queryPlanToMongoose({ queryPlan, mapper });
if (result.kind === PlanKind.ALWAYS_DENIED) {
return [];
}
const filters = result.kind === PlanKind.CONDITIONAL ? result.filters : {};
const records = await MyModel.find(filters);
Combine with existing application filters using $and:
await MyModel.find({ $and: [filters ?? {}, { archived: false }] });
Field mapper
const mapper = {
"request.resource.attr.title": { field: "title" },
"request.resource.attr.owner": {
relation: { name: "owner", type: "one", field: "id" },
},
"request.resource.attr.tags": {
relation: {
name: "tags",
type: "many",
fields: { name: { field: "name" } },
},
},
};
-
field— rewrites a Cerbos path to a different field name in MongoDB -
valueParser— transforms leaf values during filter construction (for example, converting strings toObjectId) -
relation— describes embedded documents (type: "one") or arrays (type: "many") -
fields— nested overrides for lambda expressions such astag.name
Collection operators
Collection-aware operators (filter, exists, exists_one, hasIntersection, map, all) require the mapper to declare the relation with type: "many". The adapter scopes lambda variables and uses the fields map when translating expressions:
-
exists,exists_one,filter— wrap the condition in$elemMatch -
hasIntersection— supports both scalar arrays and arrays of objects; projects nested paths via$elemMatch -
all— converts the lambda condition into a negated$elemMatchso all elements must satisfy the predicate