Skip to content

reopened: BREAKING CHANGE from 8.7.2: lean query return full mongoose object type for populated doc instead of FlattenMaps #15102

Closed
@nikzanda

Description

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

8.9.0

Node.js version

20.10.0

MongoDB server version

6.0.2

Typescript version (if applicable)

5.5.4

Description

I'm reopening this issue because it was closed without resolution. You can find the closed issue at this link.
I'll try to use a simpler example to explain what the bug is:

// child.ts
import {
  Connection,
  HydratedDocument,
  Model,
  Schema,
  SchemaTypes,
  Types,
} from 'mongoose';

export interface IChild {
  _id: Types.ObjectId;
  name: string;
}

type ChildDocumentOverrides = {};

export interface IChildVirtuals {
  id: string;
}

export type ChildInstance = HydratedDocument<
  IChild,
  ChildDocumentOverrides & IChildVirtuals
>;

type ChildModelType = Model<
  IChild,
  {},
  ChildDocumentOverrides,
  IChildVirtuals,
  ChildInstance
>;

export default (connection: Connection) => {
  const childSchema = new Schema<IChild, ChildModelType>(
    {
      name: {
        type: SchemaTypes.String,
        required: true,
        trim: true,
      },
    },
    {},
  );

  return connection.model<IChild, ChildModelType>('Child', childSchema);
};
// parent.ts
import {
  Connection,
  Document,
  HydratedDocument,
  Model,
  PopulatedDoc,
  Schema,
  SchemaTypes,
  Types,
} from 'mongoose';
import { IChild } from './child';

export interface IParent {
  _id: Types.ObjectId;
  name: string;
  child: PopulatedDoc<Document<Types.ObjectId> & IChild>;
  createdAt: Date;
  updatedAt: Date;
}

type ParentDocumentOverrides = {};

export interface IParentVirtuals {
  id: string;
}

export type ParentInstance = HydratedDocument<
  IParent,
  ParentDocumentOverrides & IParentVirtuals
>;

type ParentModelType = Model<
  IParent,
  {},
  ParentDocumentOverrides,
  IParentVirtuals,
  ParentInstance
>;

export default (connection: Connection) => {
  const parentSchema = new Schema<IParent, ParentModelType>(
    {
      name: {
        type: SchemaTypes.String,
        required: true,
        trim: true,
      },
      child: {
        type: SchemaTypes.ObjectId,
        ref: 'Child',
        required: true,
      },
    },
    {},
  );

  return connection.model<IParent, ParentModelType>('Parent', parentSchema);
};

My query:

const parent = await Parent.findOne().lean();

If I execute the query in versions prior to 8.7.2, the returned type is FlattenMaps<IParent> ✅:
Image

From version 8.7.2 onwards, the type within the parent for child is Types.ObjectId or an instance of child ❌. However, this is incorrect because I executed a lean query, so child should be Types.ObjectId | FlattenMaps<IChild>:
Image

In your comment, you suggested updating the code and explicitly setting the type of the variable to be populated. However, if I do not want to populate the variable and use a lean query, the returned type should be FlattenMaps for all PopulatedDoc.
Please, review this situation and the example I provided.

Steps to Reproduce

Execute a lean query (without using "populate") on a model that contains variables of type PopulatedDoc.

Expected Behavior

No response

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions