DoneDeal0
DoneDeal0

Reputation: 6257

Mongoose aggregation: MongoError: unknown operator: $or

I want to perform a query on a mongo database with three variables: age, job, and location as an option. I use Node and Express on the server side.

I have written this:

router.post("/search", async (req, res) => {
  try {
    const { jobs, minAge, maxAge, location, maxDistance } = req.body;
   // jobs = ["Tech", "Sales"], minAge=45, maxAge = 62, location=[1.23, 4.56], maxDistance=10000 
    if (!location) {
      const user = User.aggregate([
        {$match: {
            jobs: { $or: jobs },
            age: { $gte: minAge, $lte: maxAge },
          }},
      ]).lean()
       return res.json({user})
      });
    }
 
    const user = User.aggregate([
     { $match: {
      job: { $or: job },
      age: { $gte: minAge, $lte: maxAge }
      },
        $geoNear: {
          near: { type: "Point", coordinates: location.coordinates },
          distanceField: "dist.calculated",
          maxDistance,
        },
      },
    ]).lean();
    return res.json({ user });
  } catch (err) {
    return res.json({ errorType: "search" });
  }
});

In case it might be helpful, here is the User Schema:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const userSchema = new Schema(
  {
    username: { type: String, required: true, unique: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
    age: { type: Number, min: 18 },
    job: {
      type: String,
      enum: ["Tech", "Product", "Marketing", "Sales", "HR", "Other"],
    },
    location: {
      type: { type: String, enum: ["Point"] },
      coordinates: { type: [Number] },
    },
  },
  { timestamps: true }
);

userSchema.index({ age: 1, job: 1, location: "2dsphere" });

module.exports = mongoose.model("User", userSchema);

The error is MongoError: unknown operator: $or. How to properly retrieve an array of users that match the conditions expressed in the query?

Upvotes: 2

Views: 3373

Answers (2)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17915

You need to replace job: { $or: job } with job: { $in: job } cause $in query operator validates a field's value against an array and get the documents if at least one of the element in the array matches with the field Vs $or logical operator takes in two expressions not the values and get the documents where at least one expressions is satisfied.

$in :

// jobs = ["Tech", "Sales"]

jobs: { $in: jobs }

Test : mongoplayground

$or :

{ $or: [ {jobs : 'Tech'} , {jobs : 'Sales'} ] }

Test : mongoplayground

As you're just validating against an array on same field you don't need $or operator a simple $in should work just fine. Moreover in $geoNear you might need to replace coordinates: location.coordinates with coordinates: location - I believe it's a typo.

Upvotes: 2

D. SM
D. SM

Reputation: 14480

$or is an expression-level operator, not a field-level operator. The field-level equivalent of $or is $in.

Upvotes: 0

Related Questions