doug-martin / nestjs-query

Easy CRUD for GraphQL.
https://doug-martin.github.io/nestjs-query
MIT License
820 stars 142 forks source link

[Question] How to add relation in embed document #1031

Open viennv1709 opened 3 years ago

viennv1709 commented 3 years ago

Dear @doug-martin, I'm facing with relation issue using typegoose. How can I add relations in embed document if I have a schema like this:

import { Prop, modelOption, Ref } from '@typegoose/typegoose';
import { Base } from '@typegoose/typegoose/lib/defaultClasses';

@modelOptions({ schemaOptions: { timestamps: true } })
export class TodoItemEntity extends Base {
  @Prop({ required: true })
  title!: string;

  @Prop()
  description?: string;

  @Prop({ required: true })
  completed!: boolean;

  @Prop({ default: Date.now })
  createdAt!: Date;

  @Prop({ default: Date.now })
  updatedAt!: Date;

  @Prop()
  tags!: {
    isPrimary: boolean;
    tag: Ref<TagEntity>;
  }[];

  @Prop({ default: 0 })
  priority!: number;

  @Prop()
  createdBy?: string;

  @Prop()
  updatedBy?: string;

  public get id(): string {
    // eslint-disable-next-line no-underscore-dangle
    return this._id.toHexString();
  }
}
viennv1709 commented 3 years ago

@doug-martin Can you help me to answer this question? I need it urgent.

smolinari commented 3 years ago

@viennv1709 - You mean for the tags?

You'd need to create a second class and in that class, you'd have what you have in the object.

Scott

viennv1709 commented 3 years ago

@smolinari How can I filter with array of embed documents?

smolinari commented 3 years ago

@viennv1709 - It doesn't look like that is possible. What are you trying to accomplish? Can you explain the use case?

Scott

viennv1709 commented 3 years ago

@smolinari OK. Let me explain. I have a user entity that allow users can add more their emails. And I want to to query the user with the emails that exists in list. For example user A has 2 emails: abc@abc.com and def@def.com. I would like to query the user with email is abc@abc.com with structure like this:

import { Prop, ModelOptions } from '@typegoose/typegoose';
import { Base } from '@typegoose/typegoose/lib/defaultClasses';
import { Types } from 'mongoose';

export enum Gender {
  MALE,
  FEMALE,
  NONBINARY,
  UNKNOWN,
}

export enum NotificationEmail {
  ACCOUNT,
  UPDATES,
  PROMOTIONS,
}

export enum ColorMode {
  LIGHT,
  DARK,
}

export enum UserRole {
  ADMIN,
  USER,
}

export enum TfaMethod {
  NONE,
  SMS,
  TOTP,
  EMAIL,
}

@ModelOptions({ schemaOptions: { _id: false } })
export class Email {
  @Prop({ required: true, index: true })
  email: string;

  @Prop({ required: true, index: true })
  emailSafe: string;

  @Prop({ default: false })
  isPrimary: boolean;

  @Prop({ default: false })
  isVerified: boolean;
}

@ModelOptions({ schemaOptions: { _id: false } })
export class Address {
  @Prop({ required: true, trim: true })
  country: string;

  @Prop({ required: true, trim: true })
  state: string;

  @Prop({ required: true, trim: true })
  city: string;

  @Prop({ required: true, trim: true })
  street: string;

  @Prop({ required: true, trim: true })
  zipCode: string;

  @Prop({ default: false })
  isPrimary: boolean;
}

@ModelOptions({ schemaOptions: { _id: false } })
export class Preferences {
  @Prop({ default: 'en-us' })
  language: string;

  @Prop({ default: 'America/Los_Angeles' })
  timezone: string;

  @Prop({ enum: NotificationEmail, default: NotificationEmail.ACCOUNT })
  notificationEmail: NotificationEmail;

  @Prop({ enum: ColorMode, default: ColorMode.LIGHT })
  colorMode: ColorMode;
}

@ModelOptions({ schemaOptions: { _id: false } })
export class Tfa {
  @Prop({ enum: TfaMethod, default: TfaMethod.NONE })
  method: TfaMethod;

  @Prop()
  secret?: string;
}

@ModelOptions({ schemaOptions: { timestamps: true, collection: 'users' } })
export class UserEntity implements Base {
  _id: Types.ObjectId;

  id: string;

  @Prop({ required: true, index: true })
  name: string;

  @Prop()
  password?: string;

  @Prop({ enum: Gender, default: Gender.UNKNOWN })
  gender: Gender;

  @Prop({ default: 'https://unavatar.now.sh/fallback.png' })
  avatarUrl: string;

  @Prop({ index: true, sparse: true })
  phoneNumber?: string;

  @Prop({ default: false })
  phoneNumberVerified: boolean;

  @Prop({ type: () => [Email], default: [] })
  emails: Email[];

  @Prop({ type: () => [Address], default: [] })
  addresses: Address[];

  @Prop({ type: () => Preferences, default: new Preferences() })
  preferences: Preferences;

  @Prop({ type: () => Tfa, default: new Tfa() })
  tfa: Tfa;

  @Prop({ enum: UserRole, default: UserRole.USER })
  role: UserRole;

  @Prop({ default: false })
  active: boolean;

  @Prop({ default: Date.now })
  createdAt: Date;

  @Prop({ default: Date.now })
  updatedAt: Date;
}
smolinari commented 3 years ago

Yeah, unfortunately, nestjs-query doesn't support filtering on arrays as I can tell (and yet). So, best bet for now is to create a custom service and add such a method using model.find.

Scott