question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

$exists operator does not work on mongoose document

See original GitHub issue

Describe the bug

{ $exists: boolean } operator does not work on mongoose document. With the same ability and a plain object it works fine.

To Reproduce

package.json

{
  "name": "example",
  "main": "index.js",
  "scripts": {
    "start": "node src/index.js"
  },
  "dependencies": {
    "@casl/ability": "^6.1.1",
    "mongoose": "^6.6.0"
  }
}

src/Post.js

const mongoose = require("mongoose");

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

module.exports = mongoose.model("Post", Post);

src/defineAbility.js

const { defineAbility } = require("@casl/ability");

module.exports = defineAbility((can, cannot) => {
  can("manage", "Post", {
    author: { $exists: true },
  });
});

src/index.js

const ability = require("./defineAbility");
const subject = require("@casl/ability").subject;
const PostModel = require("./models/Post.js");

const draftPost = new PostModel({ title: "Lorem Draft" });
const myPost = new PostModel({
  title: "Lorem Ipsum",
  author: "Max Mustermann",
});

console.log("With mongoose");
console.log("can read draftPost", ability.can("read", draftPost)); // expected: false -> result: false
console.log("can read myPost", ability.can("read", myPost)); // expected: true -> result: false

console.log("With plain object");
console.log(
  "can read draftPost",
  ability.can("read", subject("Post", draftPost.toObject())) // expected: false -> result: false
);
console.log(
  "can read myPost",
  ability.can("read", subject("Post", myPost.toObject())) // expected: true -> result: true
);

Output

With mongoose
can read draftPost false
can read myPost false

With plain object
can read draftPost false
can read myPost true

Expected behavior

Supports $exists operator on mongoose documents.

CASL Version

@casl/ability - v6.1.1

Environment:

Node.js - v16.17.0

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
stalniycommented, Sep 18, 2022

OK, by looking into mongoose I see that it defines properties on model prototype. So,

console.log(myPost.hasOwnProperty('author')) // false
console.log(myPost.constructor.prototype.hasOwnProperty('author')) // true

And this is how $exists checks the existence -> https://github.com/stalniy/ucast/blob/master/packages/js/src/interpreters.ts#L70 . It requires property to be defined on the object itself.

Looking at sift.js it also uses hasOwnProperty but mingo.js gets the actual property.

Based on Mongo docs:

When <boolean> is true, $exists matches the documents that contain the field, including documents where the field value is null. If <boolean> is false, the query returns only the documents that do not contain the field

So, it’s hard to judge whether document contain the field should be true if the field is actually in its prototype.

In your case, I think better to check based on empty string or write your own $exists that will work according to your expectations (i.e., checks whether property in object or its prototype chain). Check this guide for further details -> https://casl.js.org/v6/en/advanced/customize-ability

1reaction
stalniycommented, Sep 18, 2022

that’s why $exists for mongoose documents always returns false

Read more comments on GitHub >

github_iconTop Results From Across the Web

Find all docs where field doesn't exists, plus if field exists ...
In the stackoverflow collection, this will find all documents that do not have the howmuch field plus all documents that do have howmuch...
Read more >
[Solved]-Mongoose {$exists: false} not working, why?-mongodb
It occurs with all Default value'd fields, mongoose just automatically sets these values to their defaulted value on the return call (if you...
Read more >
$exists — MongoDB Manual
MongoDB $exists does not correspond to SQL operator exists . For SQL exists , refer to the $in operator. Tip ...
Read more >
The mongoose exists function - ObjectRocket
The exists() method returns a boolean value, i.e. either true or false. This method checks if a particular document exists in a collection...
Read more >
Mongoose v6.8.2: Schemas
In these cases, Mongoose only creates actual schema paths for leaves in the tree. (like meta.votes and meta.favs above), and the branches do...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found