I have two related objects in my Mongoose data store connected by an ObjectId
reference but when I have queried both sides of the relationship independently it seems surprisingly hard to match them up. The problem might be exaggerated because I am working in Typescript. For a stripped-down example, when I have a PlanUser
who has many Plan
objects:
export interface PlanUser {
_id: string;
name: string;
email: string;
}
export interface Plan extends PlanSummary {
_id: string;
name: string;
owner: PlanUser;
}
class PlanUserSchemaClass {
public static userSchema: Schema<PlanUser> = new Schema<PlanUser>({
name: { type: String, required: true },
email: { type: String, required: true },
}, { autoCreate: false });
public static planSchema: Schema<Plan> = new Schema<Plan>({
name: { type: String, required: true },
owner: { type: Schema.Types.ObjectId, ref: 'PlanUser' },
}, { autoCreate: false });
}
export class PlanUserModel {
private planModel = model('Plan', PlanUserSchemaClass.planSchema);
private userModel = model('PlanUser', PlanUserSchemaClass.userSchema);
public async findPlan( id: string, (next: Plan) => void) {
await this.connect();
const found = await this.planModel.findById(id);
next(found);
}
public async findUser( id: string, (next: PlanUser) => void) {
await this.connect();
const user = await this.userModel.findById(id);
next(user)
}
}
Now I can query these well enough, the problem is that when I have queried them at separate points, I end up with this situation:
planUserModel.findUser('abc123', (user: PlanUser) => {
planUserModel.findPlan('def456', (plan: Plan ) => {
plan.owner == user // doesn't compile because Typescript thinks the owner is a PlanUser type
plan.owner._id == user._id // false
plan.owner._id.toString() == user._id.toString() // true
});
});
The only test that seems to work consistently is casting both _id
fields to strings.
As far as I can tell this is something to do with the ObjectId
type; possibly because I am treating the _id
fields as strings in my interface definition, but then Mongoose is populating them as ObjectId
s at runtime. It makes sense for them to strings when I am passing them up to the UI which doesn't know what the back-end data store is. It's not a huge hassle to recast everything to perform the checks if that's necessary, but it feels inelegant and as though I am going against the flow of what Mongoose expects. What is the more correct way to do this?