Setup
Let's say we have schemas for Foo and Bar. Foo has a field bar. This field can either contain an ObjectId that reference a document Bar, or it could contain other arbitrary objects that are not ObjectIds.
const fooSchema = new mongoose.Schema({
bar: {
type: mongoose.Schema.Types.Mixed,
ref: 'Bar'
}
});
const Foo = <any>mongoose.model<any>('Foo', fooSchema);
const barSchema = new mongoose.Schema({
name: String
});
const Bar = <any>mongoose.model<any>('Bar', barSchema);
Problem
Now suppose we have a bunch of Foo documents.
I would like to be able to use mongoose's populate on the bar field to automatically replace references to a Bar document with the actual Bar document itself. I would also like to leave all other objects that are not references to a Bar document unchanged.
Normally, I would use something like this to get all the Foo documents and then populate the bar field:
Foo.find().populate('bar')
However, this method will throw an exception when it encounters objects in the bar field that are not ObjectIds, as opposed to leaving them untouched.
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): CastError: Cast to ObjectId failed for value "Some arbitrary object" at path "_id" for model "Bar"
Attempt at finding a solution
I have examined using the match option on populate, by requiring that a field on Bar exists:
Foo.find().populate({
path: 'bar',
match: {
name: {
$exists: true
}
}
}
Unfortunately, the error is the same.
Question
So my question is then, is there any way to get mongoose to only populate a field if the field contains an ObjectId, and leave it alone otherwise?