-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Description
The permission validation logic in updateOne, findOneAndUpdate, and updateMany simulates updates by constructing an aggregation pipeline from the update operators:
const pipeline = [
{ $match: { $and: safeQuery } },
{ $limit: 1 },
...Object.entries(data).map(([key, value]) => ({ [key]: value }))
];
[docToCheck] = yield collection.aggregate(pipeline).toArray();This works for $set because $set is both a valid update operator and a valid aggregation pipeline stage. However, $inc, $push, $pull, $addToSet, and $unset (as update operators) are not valid aggregation stages. MongoDB throws Unrecognized pipeline stage name: '$inc'.
In Realm, all update operators work without issue because Realm does not simulate updates as aggregation pipelines for permission checks.
Steps to reproduce
// With a non-system user and collection rules that allow updates:
exports = async function () {
const db = context.services.get("mongodb-atlas").db("mydb");
const col = db.collection("orders");
// This works:
await col.updateOne({ _id: someId }, { $set: { status: "done" } });
// This throws "Unrecognized pipeline stage name: '$inc'":
await col.updateOne({ _id: someId }, { $inc: { count: 1 } });
// Same for $push, $pull, $addToSet, $unset:
await col.updateOne({ _id: someId }, { $push: { tags: "new" } });
};Expected behavior
All standard MongoDB update operators should work when the user has permission to update the document. The validation approach needs to handle operators that aren't valid aggregation stages.
Impact
Any non-system function using $inc, $push, $pull, $addToSet, or $unset in update operations fails. These are standard MongoDB operators used in virtually every production application. In Realm, these work without issue.