2

I have two Mongoose schemas:

var EmployeeSchema = new Schema({
    name: String,
    servicesProvided: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Service'
    }]
});

var ServiceSchema = new Schema({
    name: String
});

I'm trying to find employees who provide a specified service with the service ID I send into the http request. This is my code:

Employee
  .find({
    servicesProvided: req.params.service_id
  })
  .exec(function(err, employees) {
    if (err) {
      console.log(err);
      res.send(err);
    } else {
      res.json(employees);
    }
});

The problem is that this code returns an empty array and I don't know why. I've tried a lot of things like casting the service id to mongoose.Schema.Types.ObjectId but it doesn't work.

Any idea? I'm using Mongoose 3.8.39. Thanks!

alexmac
  • 19,087
  • 7
  • 58
  • 69
gonver
  • 349
  • 1
  • 12

2 Answers2

3

In your EmployeeSchema, servicesProvided is an array, to filter employees by that field you should use $in operator:

var services = [req.params.service_id];
Employee.find({
  servicesProvided: {
    $in: services
  }
}, ...
alexmac
  • 19,087
  • 7
  • 58
  • 69
  • This searches for documents **inside provided array** which is bad overhead. – Andrey Popov Apr 07 '16 at 16:40
  • @AndreyPopov With index or small lists It can be fairly efficient. – alexmac Apr 07 '16 at 16:44
  • I agree, but still it's not needed. Today it's a small list, tomorrow it's a huge bottleneck :) If you can make it easier from the beginning - why not? – Andrey Popov Apr 07 '16 at 16:48
  • Thank you for your answer, it works properly but I'll choose the other answer if is more efficient. – gonver Apr 07 '16 at 16:57
  • Np, I agree that solution suggested by @AndreyPopov is more preferable in that concrete scenario. – alexmac Apr 07 '16 at 17:02
  • @Alexander - this is an interesting one. I've seen a few suggestions like mine, but I just stumbled upon [this](https://github.com/Automattic/mongoose/issues/2804) which actually says `If managers is an array of ObjectId, you should just use .. $in`. Quite strange. I've tested it locally and it works properly using simple single elem match query (but on a fake sandboxed app). Should investigate with real app :) Of course yours works too – Andrey Popov Apr 07 '16 at 17:25
  • Check this out: http://stackoverflow.com/questions/12451358/mongoose-mongo-find-in-array-of-objectids – Andrey Popov Apr 07 '16 at 17:28
  • @AndreyPopov That's strange for me too, I've checked `$elemMatch` operator in my real app, on the collection simular to TC collection, and it's working well. But that issue in mongoose... Anyway, I'm always using `$in` operator, and this never was the problem:). – alexmac Apr 07 '16 at 18:36
2

I think you need $elemMatch! From docs:

{ _id: 1, results: [ { product: "abc", score: 10 }, { product: "xyz", score: 5 } ] },
{ _id: 2, results: [ { product: "abc", score: 8 }, { product: "xyz", score: 7 } ] },
{ _id: 3, results: [ { product: "abc", score: 7 }, { product: "xyz", score: 8 } ] }

Search like:

db.survey.find({ results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } })

Results in:

{ "_id" : 3, "results" : [ { "product" : "abc", "score" : 7 }, { "product" : "xyz", "score" : 8 } ] }

But since you're doing a single query condition (look at the docs again) you can replace

db.survey.find(
   { results: { $elemMatch: { product: "xyz" } } }
)

with

db.survey.find(
   { "results.product": "xyz" }
)

So in your case it should be something like:

find({
    'servicesProvided': ObjectId(req.params.service_id)
})
Andrey Popov
  • 7,362
  • 4
  • 38
  • 58
  • Sorry, It does not work either answers. Your first one returns an empty array and the second one returns a reference error : ObjectId is not defined. If I use mongoose.Schema.Types.Object(req.params.service_id) doesn't work either. – gonver Apr 07 '16 at 17:03
  • I don't know what's my 'first' and 'second' one, and why it's not working, as this should be the proper way (even tested it locally). Not sure what's going on at your place. You can accept the other answer if it suits your needs, but keep in mind to test it out what's going on and why this is not working. Again, check the online manual just to be sure ;) – Andrey Popov Apr 07 '16 at 17:20
  • http://stackoverflow.com/questions/12451358/mongoose-mongo-find-in-array-of-objectids – Andrey Popov Apr 07 '16 at 17:28
  • Your first answer was: `'servicesProvided': req.params.service_id` and your second one: `'servicesProvided._id': ObjectId(req.params.service_id)`. I'm sure that is the proper way but for some reason it doesn't work. I've read about this problem in many internet forums, maybe is a bug of a Mongoose version. – gonver Apr 07 '16 at 17:30