# @casl/mongoose 中文文档

规范地址：https://npmcn.com/package/%40casl/mongoose/

版本：9\.1\.0
npm 元数据更新时间：2026-10-28T15:04:46.190Z
中文译文更新时间：2026-11-09T04:05:45.955Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40casl/mongoose
原文对照：https://npmcn.com/package/%40casl/mongoose/?lang=original
项目主页：https://casl.js.org/
源码仓库：https://github.com/stalniy/casl

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：36.1 kB，11 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：mongoose ^6\.0\.13 \|\| ^7\.0\.0 \|\| ^8\.0\.0 \|\| ^9\.0\.0，@casl/ability ^7\.0\.0
- 首次发布：2018-02-22T20:17:15.932Z
- 最新版本发布：2026-10-28T15:04:44.830Z
- 近 30 天下载量：219349（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：51（近 12 个月 7 个）

## 中文简介

允许根据 CASL 规则向 MongoDB 查询可访问的记录

## 安装

```sh
npm install @casl/mongoose
```

也可以使用：`pnpm add @casl/mongoose`、`yarn add @casl/mongoose`、`bun add @casl/mongoose`

## README

# 卡塞尔蒙哥

[![@casl/mongoose NPM version](https://badge.fury.io/js/%40casl%2Fmongoose.svg)](https://badge.fury.io/js/%40casl%2Fmongoose) [![](https://img.shields.io/npm/dm/%40casl%2Fmongoose.svg)](https://www.npmjs.com/package/%40casl%2Fmongoose) [![Support](https://img.shields.io/badge/Support-github%20discussions-green?style=flat&link=https://github.com/stalniy/casl/discussions)](https://github.com/stalniy/casl/discussions)

此软件包集成 [卡塞尔](https://github.com/stalniy/casl) 财务报告和审定财务报表 [蒙戈DB](https://www.mongodb.com/),换句话说,它允许根据CASL规则从MongoDB获取记录并回答诸如"哪些记录可以读取"或"哪些记录可以更新"之类的问题.

## 安装

```sh
npm install @casl/mongoose @casl/ability
# or
yarn add @casl/mongoose @casl/ability
# or
pnpm add @casl/mongoose @casl/ability
```

## 使用量

`@casl/mongoose` 不仅可以与 [鸽子](http://mongoosejs.com/) 但与任何 [蒙戈DB](https://www.mongodb.com/) 联合来文司机 `accessibleBy` 帮助函数 .

### `accessibleBy` 帮助者

这种整洁的帮助器功能可以将能力规则转换为MongoDB查询,只从数据库取取取可访问的记录. 它可以用来与绵羊或 [MongoDB 适配器](https://mongodb.github.io/node-mongodb-native/)数字 :

#### MongoDB 适配器

```js
const { accessibleBy } = require('@casl/mongoose');
const { MongoClient } = require('mongodb');
const ability = require('./ability');

async function main() {
  const db = await MongoClient.connect('mongodb://localhost:27017/blog');
  let posts;

  try {
    posts = await db.collection('posts').find(accessibleBy(ability, 'update').ofType('Post'));
  } finally {
    db.close();
  }

  console.log(posts);
}
```

这也可以与其他条件相结合,帮助: `$and` 运算符 :

```js
posts = await db.collection('posts').find({
  $and: [
    accessibleBy(ability, 'update').ofType('Post'),
    { public: true }
  ]
});
```

**重要的东西!**:永远不要使用散开运算符(即, `...`将下列条件结合起来: `accessibleBy` 由于您可能无意中覆盖了限制访问特定记录的属性:

```js
// returns { authorId: 1 }
const permissionRestrictedConditions = accessibleBy(ability, 'update').ofType('Post');

// DANGER DO NOT DO THIS (see above use $and)
const query = {
  // This is bad and potentially wrong code
  ...permissionRestrictedConditions,
  authorId: 2
};
```

上面的情况,我们翻唱 `authorId` 基本上允许未经许可进入作者的 `id = 2`

如果没有定义特定动作/主题的权限, `accessibleBy` 将返回 `{ $expr: { $eq: [0, 1] } }` 当它被发送到MongoDB时,数据库会返回一个空结果集.

#### 乌鸦

```js
const Post = require('./Post') // mongoose model
const ability = require('./ability') // defines Ability instance

async function main() {
  const accessiblePosts = await Post.find(accessibleBy(ability).ofType('Post'));
  console.log(accessiblePosts);
}
```

历史上, `@casl/mongoose` 本来是为了实现与 [鸽子](http://mongoosejs.com/) 但是现在我们重新调整它的方向 是更多的蒙戈DB 特定的包,因为复杂的工作 与mongoose类型 在TS.

### 可访问的记录插件

此插件已贬值, 建议使用的方法 [`accessibleBy` 帮助函数](https://npmcn.com/package/%40casl/mongoose/#readme-accessibleBy-helper)。 。 。 .

`accessibleRecordsPlugin` 是一个添加的插件 `accessibleBy` (a) 探询方法以及梦游模型的静态方法。 我们可以在全球添加这个插件 :

```js
const { accessibleRecordsPlugin } = require('@casl/mongoose');
const mongoose = require('mongoose');

mongoose.plugin(accessibleRecordsPlugin);
```

> 在调用前确保添加插件 `mongoose.model(...)` 方法。 Mongoose 不会在调用前创建的模型中添加全局插件 `mongoose.plugin()`。 。 。 .

或特定型号:

```js
const mongoose = require('mongoose')
const { accessibleRecordsPlugin } = require('@casl/mongoose')

const Post = new mongoose.Schema({
  title: String,
  author: String
})

Post.plugin(accessibleRecordsPlugin)

module.exports = mongoose.model('Post', Post)
```

之后,我们可以使用 `accessibleBy` 方法打开 `Post`数字 :

```js
const Post = require('./Post')
const ability = require('./ability') // defines Ability instance

async function main() {
  const accessiblePosts = await Post.accessibleBy(ability);
  console.log(accessiblePosts);
}
```

> 见 [CASL 指南](https://casl.js.org/v7/en/guide/intro) 学会如何定义能力

或在现有查询实例中:

```js
const Post = require('./Post');
const ability = require('./ability');

async function main() {
  const accessiblePosts = await Post.find({ status: 'draft' })
    .accessibleBy(ability)
    .select('title');
  console.log(accessiblePosts);
}
```

`accessibleBy` 返回实例 `mongoose.Query` 也就是说你可以用任何 `mongoose.Query`方法(例如:, `select`, (中文(简体) ), `limit`, (中文(简体) ), `sort`) (中文(简体) ). 默认, `accessibleBy` 基于规则列表构建查询 `read` 动作,但我们可以通过提供第二个可选参数来改变这一点:

```js
const Post = require('./Post');
const ability = require('./ability');

async function main() {
  const postsThatCanBeUpdated = await Post.accessibleBy(ability, 'update');
  console.log(postsThatCanBeUpdated);
}
```

> `accessibleBy` 建在顶部 `rulesToQuery` 函数从 `@casl/ability/extra`读取 [数据库查询能力](https://casl.js.org/v7/en/advanced/ability-to-database-query) 来了解它是如何运作的.

如果用户没有权限做特定动作, CASL 会丢弃 `ForbiddenError` 并且不会向MongoDB发送请求。 它还说 `__forbiddenByCasl__: 1` 附加安全条件.

例如,让我们找到所有用户可以删除的帖子(我们还没有定义删除的能力):

```js
const { defineAbility } = require('@casl/ability');
const mongoose = require('mongoose');
const Post = require('./Post');

mongoose.set('debug', true);

const ability = defineAbility(can => can('read', 'Post', { private: false }));

async function main() {
  try {
    const posts = await Post.accessibleBy(ability, 'delete');
  } catch (error) {
    console.log(error) // ForbiddenError;
  }
}
```

我们还可以利用由此产生的条件: [管道合计](https://mongoosejs.com/docs/api.html#aggregate_Aggregate)数字 :

```js
const Post = require('./Post');
const ability = require('./ability');

async function main() {
  const query = Post.accessibleBy(ability)
    .where({ status: 'draft' })
    .getQuery();
  const result = await Post.aggregate([
    {
      $match: {
        $and: [
          query,
          // other aggregate conditions
        ]
      }
    },
    // other pipelines here
  ]);
  console.log(result);
}
```

或进入 [映射图](https://mongoosejs.com/docs/api.html#model_Model.mapReduce)数字 :

```js
const Post = require('./Post');
const ability = require('./ability');

async function main() {
  const query = Post.accessibleBy(ability)
    .where({ status: 'draft' })
    .getQuery();
  const result = await Post.mapReduce({
    query: {
      $and: [
        query,
        // other conditions
      ]
    },
    map: () => emit(this.title, 1);
    reduce: (_, items) => items.length;
  });
  console.log(result);
}
```

### 可访问字段By

`accessibleFieldsBy` 允许为主题类型或具体主题实例检索可用的字段 :

```ts
import { accessibleFieldsBy } from '@casl/mongoose';
import { Post } from './models';

accessibleFieldsBy(ability).ofType('Post') // returns accessible fields for Post model
accessibleFieldsBy(ability).ofType(Post) // also possible to pass class if classes are used for rule definition
accessibleFieldsBy(ability).of(new Post()) // returns accessible fields for Post model
```

这个帮助器可以在我们只需要发送一个模型中可访问的部分响应时直接使用:

```js
const pick = require('lodash/pick');
const { accessibleFieldsBy } = require('@casl/mongoose');
const Post = require('./Post');

app.get('/api/posts/:id', async (req, res) => {
  const post = await Post.accessibleBy(ability).findByPk(req.params.id);
  res.send(pick(post, accessibleFieldsBy(ability).of(post)));
});
```

当用模型类型调用时, `accessibleFieldsBy` 不考虑实例条件。 也一样 [检查逻辑](https://casl.js.org/v7/en/guide/intro#checking-logic) 作为 `Ability`是因为 `can` 方法。 让我们举个例子来回顾一下:

```js
const { defineAbility } = require('@casl/ability');
const Post = require('./Post');

const ability = defineAbility((can) => {
  can('read', 'Post', ['title'], { private: true });
  can('read', 'Post', ['title', 'description'], { private: false });
});
const post = new Post({ private: true, title: 'Private post' });

accessibleFieldsBy(ability).ofType(Post); // ['title', 'description']
accessibleFieldsBy(ability).of(post); // ['title']
```

如您所见, 模式级访问返回所有可以读取的字段 。 同时,可读取此特性的例级访问返回字段 `post` 举个例子 所以除了减少应用软件和数据库之间的流量之外 通常没什么意义 把模型级访问的结果传入 `mongoose.Query`是因为 `select` 方法 因为你最终需要调用 `accessibleFieldsBy` 在每一个例子.

此助手已预配置以获取全部字段 `Model.schema.paths`。如果不需要,请定义您的自定义助手 :

```ts
import { AnyMongoAbility, Generics } from "@casl/ability";
import { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from "@casl/ability/extra";
import mongoose from 'mongoose';

const getSubjectTypeAllFieldsExtractor: GetSubjectTypeAllFieldsExtractor = (type) => {
  /** custom implementation of returning all fields */
};

export function accessibleFieldsBy<T extends AnyMongoAbility>(
  ability: T,
  action: Parameters<T['rulesFor']>[0] = 'read'
): AccessibleFields<Extract<Generics<T>['abilities'], unknown[]>[1]> {
  return new AccessibleFields(ability, action, getSubjectTypeAllFieldsExtractor);
}
```

## 在mongoose中支持脚本类型

软件包被用TypeScript写出,这使得与插件和帮助器一起工作更容易,因为IDE提供了有用的提示. 让我们看看它的行动!

如果我们有 `Post` 可称为:

```ts
import mongoose from 'mongoose';

export interface Post extends mongoose.Document {
  title: string
  content: string
  published: boolean
}

const PostSchema = new mongoose.Schema<Post>({
  title: String,
  content: String,
  published: Boolean
});

export const Post = mongoose.model('Post', PostSchema);
```

延长 `Post` 模式为 `accessibleBy` 方法足以包含相应的插件(全球或本地在 `Post`)和相应的使用 `Model` 类型。 所以,让我们改变这个例子,所以它包括 `accessibleRecordsPlugin`数字 :

```ts
import { accessibleRecordsPlugin, AccessibleRecordModel } from '@casl/mongoose';

// all previous code, except last line

PostSchema.plugin(accessibleRecordsPlugin);

export const Post = mongoose.model<Post, AccessibleRecordModel<Post>>('Post', PostSchema);

// Now we can safely use `Post.accessibleBy` method.
Post.accessibleBy(/* parameters */)
Post.where(/* parameters */).accessibleBy(/* parameters */);
```

`accessibleFieldsBy` 不需要针对老鼠的种类。 您可以直接使用模型或文档:

```ts
import { accessibleFieldsBy } from '@casl/mongoose';

accessibleFieldsBy(ability).ofType(Post);

const post = new Post();
accessibleFieldsBy(ability).of(post);
```

如果您想要类似已删除插件的模型或文档实例方法, 请在周围创建一个小型的 app级包装 `accessibleFieldsBy` 这符合你自己的打字和现场曝光规则.

## 想帮忙吗?

想要提交错误, 提供一些代码, 还是改进文档 ? 不错! 阅读指南 [捐款](https://github.com/stalniy/casl/blob/main/CONTRIBUTING.md)。 。 。 .

如果你想帮助我们 维持我们的社区和项目,考虑 [成为开放集体的出资人](https://opencollective.com/casljs/contribute)

> 见 [支助CASL](https://casl.js.org/v7/en/support-casljs) 详情

## 许可证

[MIT 许可证](http://www.opensource.org/licenses/MIT)

## 常见问题

### @casl/mongoose 是什么？

允许根据 CASL 规则向 MongoDB 查询可访问的记录

### 如何安装 @casl/mongoose？

在项目目录运行 npm install @casl/mongoose，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：mongoose（^6\.0\.13 \|\| ^7\.0\.0 \|\| ^8\.0\.0 \|\| ^9\.0\.0）、@casl/ability（^7\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @casl/mongoose 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @casl/mongoose 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @casl/mongoose 可以商用吗？

@casl/mongoose 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @casl/mongoose 的下载量有多少？

根据 npm 官方下载统计，@casl/mongoose 在 2026/10/09 – 2026/11/07 这 30 天内被下载 219,349 次，日均约 7,312 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @casl/mongoose 还在维护吗？

最新版本 9\.1\.0 发布于 2026/10/28（11 天前）；至今共发布 51 个版本，其中过去 12 个月发布了 7 个；首次发布于 2018/02/23。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

