Add a new field to the Typegoose subdocument

444 Views Asked by At

How do I include an extra field in the User class subdocument?

class Car {
  @prop()
  public model?: string;
}

class User {
  @prop()
  public name?: string;

  @prop({ required: true })
  public age!: number; 

  @prop({ ref: () => Car })
  public cars?: Ref<Car>[]; 
}

Populated Car Collection:

Car A
{
  "_id": "1"
  "model": "Ferrari"
}

Car B
{
  "_id": "2"
  "model": "Tesla"
}

User collection populated according to the default class:

User
{
  "_id": "1",
  "name": "Jonh Doe",
  "age": 25,
  "cars": [
    { "_id": "1" },
    { "_id": "2" }
  ]
}

I need to include a "status" field in the cars array of the User collection, as shown below:

  • status is to identify whether the car model is active for the user
User
{
  "_id": "1",
  "name": "Jonh Doe",
  "age": 25,
  "cars": [
    { "_id": "1", "status": false },
    { "_id": "2", "status": true }
  ]
}

1

There are 1 best solutions below

0
willmartinsmg On BEST ANSWER

Hasezoey helped me with the github issue.

Here's the link and his answer.

https://github.com/typegoose/typegoose/discussions/726

You have multiple options:

make the current reference array a subdocumentarray (see example 1) include the status property on the car itself have a separate class that has a unique compound index on the user-car references and has the properties you want and have such a reference field in the user (either through virtual populate or with a explicit ref array) (see example 2)

Example 1:

class Car {
  @prop()
  public model?: string;
}

class UserCarSub {
  @prop({ ref: () => Car })
  public car: Ref<Car>;

  @prop()
  public extra_properties: string;
}

class User {
  @prop()
  public name?: string;

  @prop({ required: true })
  public age!: number; 

  @prop()
  public cars?: UserCarSub[];
}

Example 2:

// the first example does not use virtual populate
class Car {
  @prop()
  public model?: string;
}

class UserCarProperties {
  @prop({ ref: () => Car })
  public car: Ref<Car>;

  @prop({ ref: () => User })
  public user: Ref<User>;

  @prop()
  public extra_properties: string;
}

class User {
  @prop()
  public name?: string;

  @prop({ required: true })
  public age!: number; 

  @prop({ ref: () => Car })
  public cars?: Ref<Car>[]; 

  @prop({ ref: () => UserCarProperties })
  public car_properties: Ref<UserCarProperties>[];
}

// the following uses virtual populate
class User {
  @prop()
  public name?: string;

  @prop({ required: true })
  public age!: number; 

  @prop({ ref: () => Car })
  public cars?: Ref<Car>[]; 

  @prop({ ref: () => UserCarProperties, foreignField: 'user', localField: '_id' })
  public car_properties: Ref<UserCarProperties>[]; // this property does not exist in the database, but can still populate
}

Virtual Populate

Alternatively you could also in Example 2 merge the cars references into the UserCarProperties and use that to find cars, that is fully up to how you want it

Personally i would suggest Example 2 with virtual populate (merged) if the array is of unknown length or could grow to unknown length