Access control

Alternative collections

Use alternative collections to resolve roles based on data in different collections.

For complex scenarios where role resolution depends on data in a different collection, you can use the collection property. This performs a $lookup behind the scenes to resolve the role from the alternative collection.

The collection property accepts the following fields:

PropertyDescription
targetThe collection to look up.
targetFilterFilter applied on the target collection. Supports %% access payload placeholders. The main filter of the role still applies to the source collection.
targetFieldField in the target collection to match against. Supports root & nested object properties.
targetFieldArrayPath(Optional) When targetField is a nested property inside an array field, set this to the array field path.
localFieldField in the source collection to match against. Only supports root-level properties. Make sure this field exists in the source collection.

Matching by foreign key

The most common scenario: the source collection has a foreign key (e.g. projectID) that references the target collection's _id.

const assetCollection: MongalayerCollection<Asset> = {
    schema: assetSchema,
    access: [{
        role: "owner",
        filter: {},
        collection: {
            target: "projects",
            targetFilter: {
                "owner": { "$eq": "%%user.id" }
            },
            targetField: "_id",                    // Match target's _id
            localField: "projectID"                // Against source's projectID
        }
    }]
};

A project asset is accessible when the user is an owner of the project that the asset belongs to, determined by matching assets.projectIDprojects._id.

Matching by array field on target

When the target collection stores references to the source collection in an array field, you can reverse the lookup direction:

const assetCollection: MongalayerCollection<Asset> = {
    schema: assetSchema,
    access: [{
        role: "owner",
        filter: {},
        collection: {
            target: "projects",
            targetFilter: {
                "owner": { "$eq": "%%user.id" }
            },
            targetField: "ownerAssets",            // Array field on target containing asset IDs
            localField: "_id"                      // Match against source's _id
        }
    }]
};

Here, projects.ownerAssets is an array of asset IDs. A project asset is accessible when its _id appears in the ownerAssets array of a project owned by the user.

Matching by nested property in an array field

When the target collection stores references inside objects within an array, use targetFieldArrayPath to specify the array field and targetField for the nested property:

const projectAssetCollection: MongalayerCollection<ProjectAsset> = {
    schema: projectAssetSchema,
    access: [{
        role: "owner",
        filter: {},
        collection: {
            target: "projects",
            targetFilter: {
                "owner": { "$eq": "%%user.id" }
            },
            targetField: "id",                     // Nested property within each array element
            targetFieldArrayPath: "pendingAssets", // The array field on target
            localField: "_id"                      // Match against source's _id
        }
    }]
};

In this case, projects.pendingAssets is an array of objects like { id: "asset-1", ... }. The lookup unwinds the array and matches pendingAssets[].id against the source's _id.

Combining with a source filter

You can combine an alternative collection lookup with a filter on the source collection. Both conditions must be satisfied for the role to match:

const assetCollection: MongalayerCollection<Asset> = {
    schema: assetSchema,
    access: [{
        role: "creator",
        filter: {
            uploaderID: "%%user.id"               // Filter on source collection
        },
        collection: {
            target: "projects",
            targetFilter: {
                "owner": { "$eq": "%%user.id" }
            },
            targetField: "_id",
            localField: "projectID"
        }
    }]
};

This grants the creator role only when the user is both the uploader of the asset and an owner of the project it belongs to.

Copyright © 2026