Search code examples
mongodbmongoosenestjs

id for nested documents in array in nest.js with mongo


Is there a way to create each document inside an array with an auto-generated _id?

I am trying with this models:

// Nested Document
export class Group extends Document {
  @Prop({ required: true, unique: true, auto: true, })
  _id?: Types.ObjectId;

  @Prop({ required: true })
  count?: number;
  ...
}

// Main Document
@Schema()
export class Party extends Document {
  @Prop({ required: true })
  direction: string;

  @Prop({ type: Array<Group>, required: true, _id: true })
  groups: Array<Group>;
  ...
}

export const PartySchema = SchemaFactory.createForClass(Party);

But in my PartyService, when I create an party, nested _id's aren't being created. For example, if I run this:

create(){
  return await this.model.create({
    direction: "Main st.",
    groups: [
      {
        count: 5
      },
      {
        count: 7
      }
    ]
  });
}

It just create an document as next:

{
  _id: "a3d768f1..."
  direction: "Main st.",
  groups: [
    {
      count: 5
    },
    {
      count: 7
    }
  ],
  createdAt: ...,
  updatedAt: ...,
  ...,
}

Solution

  • In Mongoose, when you define a nested document inside an array using a schema, the subdocument's _id field is not automatically generated. This is because the subdocument is considered embedded, and Mongoose doesn't generate _id for embedded documents by default.

    In order to mitigate this challenge, you need to manually generate and assign the _id before saving the party document.

    @Injectable()
    export class PartyService {
      constructor(@InjectModel(Party.name) private model: Model<Party>) {}
    
      async create(dir, groups) {
        const party = new this.model({
          direction: dir,
          groups: groups
        });
    
        // Generate and assign _id for each group
        party.groups.forEach((group) => {
          group._id = Types.ObjectId();
        });
    
        return await party.save();
      }
    }
    

    An example of groups value as paramater to PartyService.create() could be:

    const groups = [
      {
        count: 1,
      },
      {
        count: 2,
      },
    ],