Home > OS >  Defined variable is undefined in mongoDB $where's function
Defined variable is undefined in mongoDB $where's function

Time:10-11

Long story short, I have in my MongoDB database a collection of posts and with node.js, express and mongoose, I'm trying to find all the documents using the $where method.

So I try this and it works perfectly, all the results, if their name includes Jo get returned.

app.get("/posts", (req, res) => {
  const nameSearch = "Jo";
  Post.find({
    $where: function () {
      return this.name.includes("Jo");
    },
  }).then((data) => res.send(data));
});

But if I do something like this, it throws me an error

app.get("/posts", (req, res) => {
  const nameSearch = "Jo";
  Post.find({
    $where: function () {
      return this.name.includes(nameSearch);
    },
  }).then((data) => res.send(data));
});

Also, if I do this, it says that $where requires a string or a function.

function runThis(post) {
      return post.name.includes("Jo");
}
app.get("/posts", (req, res) => {
  Post.find({
    $where: runThis(this),
  }).then((data) => res.send(data));
});

Even weirder, I think, is that if I change the function inside the $where to an arrow function, no matter what I put in the function, it will return all the results

app.get("/posts", (req, res) => {
  const nameSearch = "Jo";
  Post.find({
    $where: () => {
      return this.name.includes("Jo");
    },
  }).then((data) => res.send(data));
});

CodePudding user response:

Caveat: I don't use Mongoose or MongoDb.

But the documentation says the function you pass for $where isn't executed locally, it's executed on the Mongoose server. So it doesn't have access to the variable.

But a search (1, 2) suggests that the usual way to find a substring within a field is to use $regex. If so, and you have a user-entered string (which might contain characters that have special meaning to $regex), you'll want to escape them. So for instance:

app.get("/posts", (req, res) => {
    const nameSearch = "Jo";
    Post.find({
        name: {
            $regex: new RegExp(escapeRegex(nameSearch)),
        }),
    }).then((data) => res.send(data));
});

...where escapeRegex is from that linked question's answers. (Apparently JavaScript regular expression objects are supported, as well as strings using PCRE syntax instead.)

If for some reason you can't do that, you can also pass a string for $where, so you could create the string dynamically:

app.get("/posts", (req, res) => {
    const nameSearch = "Jo";
    Post.find({
        $where: `this.name.includes(${JSON.stringify(nameSearch)})`,
        //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    }).then((data) => res.send(data));
});

Normally, writing JavaScript code in strings is a bad idea (even though Mongoose has to convert whatever function you give it to a string to send it to the server anyway), but if you need to do this kind of substitution...

CodePudding user response:

Few things from the documentation

$where docs

About scope

Starting in MongoDB 4.4, $where no longer supports the deprecated BSON type JavaScript code with scope (BSON type 15)

You should avoid using $where

$where evaluates JavaScript and cannot take advantage of indexes. Therefore, query performance improves when you express your query using the standard MongoDB operators (e.g., $gt , $in ).

In general, you should use $where only when you cannot express your query using another operator. If you must use $where , try to include at least one other standard query operator to filter the result set. Using $where alone requires a collection scan.

About variables

I have no idea, but you can try using $let

  • Related