15

I am having issues with mongoose queries when I query by an ObjectId field. Passing mongoose.Types.ObjectId or string both throws errors. TypeScript only stops complaining when I cast the ObjectId to mongoose.Schema.Types.ObjectId, which then crashes at runtime since it's not a valid ObjectId.

interface DocumentWithTimestamp extends Document<ObjectId> {
  createdAt: Date;
  updatedAt: Date;
}

First of all, I noticed that Document defines _id as ObjectId | undefined, which already complicates everything.

I define my Schemas as follows:

export interface LanguageSchema extends DocumentWithTimestamp {
  langCode: string;
  locale: string;
}


interface LanguageModel extends Model<LanguageSchema> {
  mapToLanguage(language: LeanDocument<LanguageSchema> | LanguageSchema): Language;
}

const languageSchema = new Schema<LanguageSchema, LanguageModel>(
  {
    langCode: { type: String, required: true, trim: true },
    locale: { type: String, unique: true, required: true, trim: true },
  },
  { collection: 'language', timestamps: true, versionKey: false },
);

languageSchema.statics.mapToLanguage = function (language: LeanDocument<LanguageSchema> | LanguageSchema): Language {
  return {
    id: language._id?.toString() || '', // why is _id conditional...?
    langCode: language.langCode,
    locale: language.locale,
  };
};

export const LanguageModel = model<LanguageSchema, LanguageModel>('Language', languageSchema);

Now querying my LanguageModel by _id or any other ObjectId field throws type errors:

export async function findLanguagesByIds(languageIds: string[]) {
  return LanguageModel.find({ _id: { $in: languageIds } }).lean();
}

Error:

Argument of type '{ _id: { $in: string[]; }; }' is not assignable to parameter of type 'Callback<LanguageSchema[]>'.
      Object literal may only specify known properties, and '_id' does not exist in type 'Callback<LanguageSchema[]>'.

When I try to cast string[] to Schema.Types.ObjectId[] array, the error goes away but this cannot be the solution, since it crashes at runtime (Schema.Types.ObjectId is not a valid ObjectId).

const languages = await LanguageModel.find({
  _id: { $in: languageIds.map((id) => new mongoose.Schema.Types.ObjectId(id)) },
}).lean();

If I cast to mongoose.Types.ObjectId(to a real ObjectId) it throws errors again...

Any help is appreciated!

3 Answers 3

10

I found the solution to my problem.

mongoose Document is defined as follows:

class Document<T = any, TQueryHelpers = any, DocType = any> {
  constructor(doc?: any);

  /** This documents _id. */
  _id?: T;

  // ...
  }

I extended it using Document<ObjectId>. The ObjectId type however was the Schema type, e.g.

import { ObjectId } from "mongoose";

But it actually should have been the actual ObjectId Type of mongoose and not the Schema type!

FIX:

import { Types } from "mongoose"

interface DocumentWithTimestamp extends Document<Types.ObjectId> {
  createdAt: Date;
  updatedAt: Date;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Super confusing api from mongoose here.... they need better support. Not even sure why you have to define a model AND then an interface too... huge pain
I agree the handling of ObjectIds is confusing, but you can use the InferRawDocType import from mongoose to generate typescript types from your schema. There is another import to generate the same types from schema instances too
3

I have a dirty solution

In my case I need filter by user id, same error.

This parse fix it: as unknown as ObjectId

const userId = req.userId as unknown as ObjectId;

const res: IPostDocument[] = await Post.find({userId: userId})

Comments

0

You can also try to do like this { _id: new ObjectId(id) }

and you can import ObjectId from MongoDB import { ObjectId } from "MongoDB";

Comments

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.