14

I have this item in mongo:

[ 
  { 
    title: 'Product Name',
    _id: 5052843e023273693300013c,
    description: 'This is a fake description',
    categories: [ 5052843e023273693300010a ],
  }
]

I want to find products like this that have this category. I have tried:

Product.find({ categories:  mongoose.Types.ObjectId('5052843e023273693300010a')})
Product.find({ categories:  mongoose.mongo.BSONPure.ObjectID.fromString('5052843e023273693300010a')})
Product.find({ categories:  '5052843e023273693300010a'})
Product.find({ 'categories':  '5052843e023273693300010a'})
Product.find({ categories:  {$in: ['5052843e023273693300010a']}})
Product.find({ categories:  Schema.Types.ObjectId('5052843e023273693300010a')})

But nothing works. I can fetch by id just fine using: _id: '5052843e023273693300013c'.

Note that when the products were inserted the category ID was added as a string (meaning I just assigned the ID instead of the category objects but that doesn't explain why none of the above work - it's unquoted in the dump so perhaps Mongo recognizes as an object ID.

Similar questions on SO did not yield an answer.

I am using the latest Mongoose (3 something) and recent Mongo, Node.

Update:

I can fetch just fine from CLI using:

db.products.find({ categories: '5052843e02327369330000fe' }); 

and interestingly I can fetch it by doing the not equal in my code - huh?:

Product.find({ categories: { $ne: '5052843e02327369330000fe' }})

My schema is as follows:

var Product = new Schema({
    title: { type: String, required: true },
    slug: { type: String },
    summary: { type: String }, //browser title
    description: { type: String, required: false },
    excerpt: { type: String },    //for a list and also for the meta description
    publish: { type: Boolean },
    featured: { type: Boolean },
    unavailable: { type: Boolean },
    model: { type: String },
    google: { type: String },
    tags: { type: Array },
    categories:  [{ type: Schema.Types.ObjectId, ref: 'Category' }],
    manufacturer: { type: String },
    variations: { type: Array },
    prices: { type: Array },
    images: { type: Array },
    specs: { type: Array },
    modified: { type: Date, default: Date.now }
});
    
var Category = new Schema({
    title: { type: String, required: true },
    description: { type: String },
    parent: { type: Schema.Types.ObjectId, ref: 'Category' },
    images: { type: Array }
});

Thanks

1
  • What's the schema definition for the Product model? Commented Sep 16, 2012 at 22:49

2 Answers 2

18

With Mongoose you have to force cast your string as an ID in some cases. Usually it automatically does this for you, but in your specific case, it doesn't. The following snippet of code will get all connections that contain the passed ID.

var mongoose = require('mongoose');
Node.find({ connections: mongoose.Types.ObjectId("535c5c1b8aa6dc5f021e8a98") }, function (err, results) { 
    console.log(results); 
});
Sign up to request clarification or add additional context in comments.

3 Comments

mongoose.Types.ObjectId() is exactly what I want!
I'm starting to run into this more and more and am having trouble pinning down exactly when it happens and when it doesn't. I'm not sure if I'm running into this in a Mongoose .update with a query with { _id: { $in: [ … ] } }. What are the known cases where it happens. Anyone know why it happens?
i imported mongoose using import * as mongoose from 'mongoose';
0

What's happening is that Mongoose is casting whatever value you're using for a categories value in your Product.find call to an ObjectId as that's how categories is defined in the schema. But the document's categories value you're trying to match has a string type instead of an ObjectId so it's not matching.

To get things to work again you'll need to clean up your existing documents to match your defined schema.

5 Comments

How would my document have a string type? Doesn't the schema make sure that when I create my document (something like product.categories = req.params.categories in an expresss form) it turns my provided string into an object ID? Surely I shouldn't have to cast it on creation?
@Yashua I thought that's what you were saying here: when the products were inserted the category ID were added as a string. If you've always had the schema indicating an array of ObjectIds and you've done all your inserts through Mongoose then they should already be ObjectIds in the collection.
@Yashua From your update, if db.products.find({ categories: '5052843e02327369330000fe' }); returns your document in the CLI, then categories does contain a string and not an ObjectId in this case.
I guess what I am asking is how to insert these ID from a form as an object ID when all I have is the ID and not the related object (for example my categories get selected from a drop down in the product edit form). That's what I mean by inserted as a string. What I am finding now is that sometimes my query works which definitely seems to indicate a fluctuation in how things are stored - just not sure how to guarantee the proper insert. I do something such as var p = new Product; p.categories = req.params.categories (an post array of cat IDs) and then p.save.
@Yashua Setting p.categories to an array of string representations of ObjectIds and then calling p.save() should work fine. I just ran a test and the values saved in categories were ObjectIds, not strings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.