Search code examples
mongodbmongoosetypegoose

Is it possible to have in Mongodb (with mongoose and typegoose) an index on array of nested keys?


In mongodb (using mongoose and typegoose) is it possible to have an array index on a nested key?

export class Member extends Typegoose {
  @prop({ required: true })
  public email!: string;

  @prop({ required: true })
  private userId!: string
}

@index({ 'members.userId': 1 })
export class Group {
  @arrayProp({ items: Member })
  public members: Member[];

  @prop()
  name: string;
}

If so, how can I query this collection if I'd want to find a group by userId? Like this?

Group.findOne({ usersIds: userId })

Solution

  • yes it is possible, here is how you can do it:

    // NodeJS: 14.5.0
    // MongoDB: 4.2-bionic (Docker)
    import { getModelForClass, prop, index } from "@typegoose/typegoose"; // @typegoose/typegoose@7.3.0
    import * as mongoose from "mongoose"; // mongoose@5.9.25 @types/mongoose@5.7.32
    
    class Member {
      @prop({ required: true })
      public email!: string;
    }
    
    @index({ "members.email": 1 }, { unique: true }) // added unique to be easily testable 
    class Group {
      @prop({ type: Member })
      public members?: Member[];
    
      @prop()
      public name?: string;
    }
    
    const GroupModel = getModelForClass(Group);
    
    (async () => {
      await mongoose.connect(`mongodb://localhost:27017/`, { useNewUrlParser: true, dbName: "verifyMASTER", useCreateIndex: true, useUnifiedTopology: true });
    
      await GroupModel.create({ name: "group1", members: [{ email: "h@h.h" }] });
      try {
        await GroupModel.create({ name: "group2", members: [{ email: "h@h.h" }] });
        console.log("didnt fail");
      } catch (err) {
        // it should error
        console.log("err", err);
      }
    
      console.log(await GroupModel.listIndexes());
    
      await mongoose.disconnect();
    })();
    

    output of GroupModel.listIndexes:

    [
      { v: 2, key: { _id: 1 }, name: '_id_', ns: 'verifyMASTER.groups' },
      {
        v: 2,
        unique: true,
        key: { 'members.email': 1 },
        name: 'members.email_1',
        ns: 'verifyMASTER.groups',
        background: true
      }
    ]