81
  Campaign.find {client_id:req.param('client_id')}, (error, campaigns) ->
    if error
      response =
        error: error.message
    else
      for campaign in campaigns
        query =
          campaign_id: campaign._id
        console.log query
        CampaignResponse.find query, (err, campaignResponsesCount) ->
          console.log campaignResponsesCount

      response = campaigns

    res.json response

For some reason, this returns no results. However, there are items in CampaignResponse with that specific campaign._id. I'm pretty sure this is an issue with types and casting, but I can't figure out what to do.

Any help?

Shamoon
  • 41,293
  • 91
  • 306
  • 570

3 Answers3

168

A couple tips:

  • Try running the same query from mongodb at the command line, see if you get any results.
  • Is the "campaign_id" defined as an ObjectId in your schema? If so, try searching using the ObjectId type.

For example:

var ObjectId = require('mongoose').Types.ObjectId; 
var query = { campaign_id: new ObjectId(campaign._id) };
andyuk
  • 38,118
  • 16
  • 52
  • 52
  • 31
    Any idea why Mongoose inserts using ObjectId and then not use ObjectId when querying? – Simon H Oct 01 '14 at 11:17
  • 5
    Note that the following statements are equivalent : var ObjectId = require('mongoose').Types.ObjectId; var ObjectId = require('mongodb').BSONPure.ObjectID; – Gabriel Hautclocq Feb 09 '15 at 22:08
  • 3
    'new' may not be needed; `var query = { campaign_id: ObjectId(campaign._id) };` – Yasin Okumuş Jan 31 '19 at 13:26
  • @YasinOkumuş new is needed otherwise we'll get error : TypeError: Class constructor ObjectId cannot be invoked without 'new' – Mohamed Hamzaoui Aug 12 '23 at 16:04
  • @MohamedHamzaoui Thank you, it has been a lot of time since my comment and things may have been changed sure :) I don't even remember my comment actually and I haven't used that for a long time. Thanks for info – Yasin Okumuş Aug 14 '23 at 22:42
52

Just to improve the previous (correct) answer, i use on my projects :

String.prototype.toObjectId = function() {
  var ObjectId = (require('mongoose').Types.ObjectId);
  return new ObjectId(this.toString());
};

// Every String can be casted in ObjectId now
console.log('545f489dea12346454ae793b'.toObjectId());
Paul Rad
  • 4,820
  • 1
  • 22
  • 23
  • 11
    I'd suggest checking for such a method's presence first: `if (!String.prototype.toObjectId) { /* your implementation */ }` – Jakub Barczyk Feb 23 '16 at 20:07
  • 1
    @Paul Rad Where would you suggest it would be best to implement this? – Tom Nijs Jul 06 '16 at 22:24
  • 2
    @JakubBarczyk I'm a bit late but if you're extending built-in objects, it is actually **not** a good idea to check for their existence first *unless your script is a polyfill*, as TC39 may extend the JavaScript API in the future. This is the reason that `Array.includes` is named as it is, instead of the more fitting name `Array.contains`: Older versions of MooTools already added such a property onto `Array.prototype`, and checked to see if it existed first. MooTools' algorithm differed from the spec algorithm, and was used often enough that adding the spec version broke a lot of the web. – Jamie Ridding Nov 16 '19 at 03:59
11

Instead of using ObjectId to find by comparing your parameters simply use

Campaign.findById {req.param('client_id'),function(err,docs)}....

when finding docs using objectId findById is the most efficient way of all...

Anil
  • 3,722
  • 2
  • 24
  • 49
Ravi Joshi
  • 661
  • 7
  • 6
  • 15
    This is good for the _id property of a document. but the OP's example is querying a relation - it's looking for the client_id property. – scipilot Jun 16 '17 at 03:30