如何在CASL的Mongoose规则中实现$and逻辑?
首先明确:CASL的Mongoose适配器确实不支持直接使用$and/$or这类逻辑运算符,但可以通过规则组合或条件调整实现相同效果。文档提到的“条件对象内属性默认是AND逻辑”,指的是单个can规则里的多个字段条件会自动按AND组合(比如{ status: "active", owner: user._id }等价于MongoDB的$and组合这两个条件),但针对同一个字段的多条件逻辑(比如你遇到的数组字段的多重$elemMatch),需要特殊处理。
针对你给出的规则,分两种场景给出实现方式:
场景1:数组中存在同一个元素同时满足两个条件
如果你的需求是userPrivileges数组里有至少一个元素同时匹配userid: user._id和canWrite: true,那根本不需要$and,直接把两个条件合并到同一个$elemMatch里即可,CASL完全支持这种写法:
can("update", "Process", { userPrivileges: { $elemMatch: { userid: user._id, canWrite: true } } });
这等价于MongoDB的{ userPrivileges: { $elemMatch: { userid: ..., canWrite: ... } } },符合CASL的条件规则,因为$elemMatch内部的属性默认是AND逻辑。
场景2:数组中分别存在两个独立元素满足各自条件
如果你的需求是userPrivileges数组里至少有一个元素匹配userid: user._id,并且至少有一个元素(可以是不同的)满足canWrite: true,这时候需要用cannot规则组合来模拟AND逻辑(利用德摩根定律:A AND B 等价于 NOT (NOT A OR NOT B)):
// 先允许所有Process的update操作 can("update", "Process"); // 排除不满足条件的情况:要么没有匹配当前用户的userPrivileges元素,要么没有canWrite为true的元素 cannot("update", "Process", { userPrivileges: { $not: { $elemMatch: { userid: user._id } } } }); cannot("update", "Process", { userPrivileges: { $not: { $elemMatch: { canWrite: true } } } });
CASL的规则评估逻辑是:只要有任意一条cannot规则匹配,就会禁止该动作。所以上面的写法会排除掉两种不符合的情况,最终只有同时满足两个条件的Process才允许更新。
内容的提问来源于stack exchange,提问作者devnull69

