简体   繁体   English

具有模式数组的 NestJS mongoose 模式不会填充虚拟 ID

[英]NestJS mongose schema with array of schema doesn't populate virtual id

I have the following schema我有以下架构

export type MapDocument = Map & Document

@Schema({ 
  timestamps: true, 
  versionKey: false,
  id: true
})
export class Map {
  
  constructor(partial?: Partial<Map>) {
    if (partial)
      Object.assign(this, partial)
  }

  @IsOptional()
  @IsUUID()
  @Prop({ type: Object, default: uuidv4, required: false})
  @Exclude({ toPlainOnly: true })
  _id?: Object

  @ApiPropertyOptional({ type: String, format: 'uuid' })
  @IsOptional()
  @IsUUID()
  id?: string

  @ApiProperty()
  @IsAscii()
  @MaxLength(10)
  @Prop()
  building: string

  @ApiProperty()
  @IsInt()
  @Prop()
  @Transform(({ value }) => +value, { toClassOnly: true })  
  floor: number

  @ApiPropertyOptional({ type: Image, format: 'uuid'})
  @IsOptional()
  @IsUUID()
  @Prop({ type: String, ref: 'Image' })
  @Transform(({ value }) => new Image(value).id, { toClassOnly: true })
  image?: string

  @ApiProperty({ type: [Marker] })
  @IsArray()
  @Type(() => Marker)
  @Prop({ type: [MarkerSchema] })
  markers?: Marker[]
  
}

const MapSchema = SchemaFactory.createForClass(Map)
MapSchema.index({ building: 1, floor: 1 }, { unique: true });
const mongooseLeanVirtuals = require('mongoose-lean-virtuals')
MapSchema.plugin(mongooseLeanVirtuals);
export { MapSchema }

export class UpdateMap extends PartialType(Map) {}

Marker is declared as follows标记声明如下

export type MarkerDocument = Marker & Document

@Schema({ 
  timestamps: true, 
  versionKey: false,
  id: true
})
export class Marker {
  
  constructor(partial?: Partial<Marker>) {
    if (partial)
      Object.assign(this, partial)
  }

  @IsOptional()
  @IsUUID()
  @Prop({ type: Object, default: uuidv4, required: false})
  @Exclude({ toPlainOnly: true })
  _id?: Object

  @ApiPropertyOptional({ type: String, format: 'uuid' })
  @IsOptional()
  @IsUUID()
  id?: string

  @ApiPropertyOptional({ type: Desk, format: 'uuid'})
  @IsOptional()
  @IsUUID()
  @Prop({ type: String, required: false, ref: 'Desk' })
  @Transform(({ value }) => new Desk(value).id, { toClassOnly: true })
  desk?: string

  @ApiProperty()
  @IsNumberString()
  @Prop()
  xPercent: string

  @ApiProperty()
  @IsNumberString()
  @Prop()
  yPercent: string
  
}

const MarkerSchema = SchemaFactory.createForClass(Marker)
const mongooseLeanVirtuals = require('mongoose-lean-virtuals')
MarkerSchema.plugin(mongooseLeanVirtuals);
export { MarkerSchema }

export class UpdateMarker extends PartialType(Marker) {}

Important to note that has a field (desk) referencing another collection but I don't want these items to be stored in their own collection but as a subdocument of the 'maps' collection directly需要注意的是有一个字段(桌面)引用另一个集合,但我不希望这些项目存储在他们自己的集合中,而是直接作为“地图”集合的子文档

The 'desk' schema is declared as follows 'desk' 模式声明如下

export type DeskDocument = Desk & Document

@Schema({ 
  timestamps: true, 
  versionKey: false,
  id: true
})
@ApiExtraModels(Image)
export class Desk {

  constructor(partial?: Partial<Desk>) {
    if (partial)
      Object.assign(this, partial)
  }
  
  @IsOptional()
  @IsUUID()
  @Prop({ type: Object, default: uuidv4, required: false})
  @Exclude({ toPlainOnly: true })
  _id?: Object

  @ApiPropertyOptional({ type: String, format: 'uuid' })
  @IsOptional()
  @IsUUID()
  id?: string

  @ApiProperty({ type: Board, format: 'uuid'})
  @IsUUID('all')
  @Prop({ type: String, required: true, ref: 'Board' })
  @Transform(({ value }) => value.id, { toClassOnly: true })
  board: string

  @ApiProperty({ type: [Number] })
  @IsArray()
  @Prop({ type: () => [Number], required: true })
  relays?: number[]

  @ApiProperty()
  @IsAscii()
  @MaxLength(250)
  @Prop()
  name: string

  @ApiProperty()
  @IsAscii()
  @MaxLength(250)
  @Prop()
  description: string

  @ApiProperty()
  @IsAscii()
  @MaxLength(10)
  @Prop()
  building: string

  @ApiProperty()
  @IsInt()
  @Prop()
  @Transform(({ value }) => +value, { toClassOnly: true })  
  floor: number

  @ApiProperty()
  @IsAscii()
  @MaxLength(10)
  @Prop()
  code: string

  @ApiPropertyOptional({ type: [Image], format: 'uuid'})
  @IsOptional()
  @IsUUID('all', { each: true })
  @Prop({ type: [String], required: false, ref: 'Image' })
  @Transform(({ value }) => value.id, { toClassOnly: true })
  images?: String[]

}

const DeskSchema = SchemaFactory.createForClass(Desk)
DeskSchema.index({ board: 1, relays: 1 }, { unique: true });
const mongooseLeanVirtuals = require('mongoose-lean-virtuals')
DeskSchema.plugin(mongooseLeanVirtuals)

export { DeskSchema }

export class UpdateDesk extends PartialType(Desk) {}

The find methods tried to populate everything down to desk (no need for me to populate deeper than that) find 方法试图将所有内容填充到桌面(我不需要填充得更深)

async findAll(): Promise<Map[]> {
    return (await this.mapModel.find().populate({
      path: 'image',
      model: Image,
      transform: (doc: Image) => new Image(doc),
    }).populate({
      path: 'markers',
      model: Marker,
      transform: (doc: Marker) => new Marker(doc),
      populate: {
        path: 'desk',
        model: Desk,
        transform: (doc: Desk) => new Desk(doc),
        options: { lean: true, virtuals: true },
      }
    }).lean({ virtuals: true }).exec())
    .map(map => new Map(map))
  }

Two issues两个问题

  1. Minor : If I don't specify lean: true as an option for the desk populate I get the full mongo document.次要:如果我没有指定精益:true 作为桌面填充的选项,我会得到完整的 mongo 文档。 This is not the case for the 'markers' array which relies on the 'lean' settings对于依赖于“精益”设置的“标记”数组,情况并非如此
  2. Main : the desk object gets populated but the virtual 'id' field doesn't This is the output I get:主要:桌子 object 被填充,但虚拟“id”字段没有这是我得到的 output:
{
  "building": "A",
  "floor": 1,
  "image": {
    "name": "OfficePlan12",
    "url": "https://drive.google.com/uc?id=1H2nnIRjR2e7Z7yoVnHxLCTaYs8s5iHrT",
    "updatedAt": "2022-06-24T09:03:03.786Z",
    "id": "2b31f419-e069-4058-813e-54ce0a941440"
  },
  "updatedAt": "2022-06-26T10:19:22.650Z",
  "markers": [
    {
      "yPercent": "15.853658536585366",
      "xPercent": "18.083462132921174",
      "desk": {
        "images": [
          "b85eefee-eeca-4193-87ae-9329fad8256a",
          "692743d0-a860-4451-b313-b21a144ef387"
        ],
        "description": "Work like a boss",
        "name": "Management desk",
        "createdAt": "2022-02-19T21:12:18.832Z",
        "updatedAt": "2022-06-07T14:02:13.556Z",
        "building": "A",
        "code": "01",
        "floor": 1,
        "relays": [
          "1"
        ],
        "board": "932c3e9b-85bd-42c8-9bc0-a318eea7b036"
      },
      "updatedAt": "2022-06-26T10:19:22.650Z",
      "createdAt": "2022-06-26T10:19:22.650Z",
      "id": "a8149e84-2f62-46c3-990f-531eff82f6d5"
    }
  ],
  "id": "37dc791f-724b-44e2-baaf-bfc606385996"
}

As you can see the 'desk' object doesn't have 'id' field .如您所见, 'desk' object 没有 'id' 字段 Any help would be much appreciated, thanks任何帮助将不胜感激,谢谢

I finally found a workaround.我终于找到了解决方法。 It looks pretty bad to be fair but it does the trick.公平看起来很糟糕,但它确实有效。 Basically I modified the transform function for the 'desk' document which is the first 'outer' document of my 'inner' document 'image'.基本上,我修改了“桌面”文档的变换 function,这是我的“内部”文档“图像”的第一个“外部”文档。 The function looks as follows: function 如下所示:

transform: (doc: Desk) => new Desk((new this.deskModel(doc)).toObject({ virtuals: true })),
    options: { lean: true },
    populate: {
      path: 'images',
      model: Image,
      transform: (doc: Image) => new Image(doc)
    }

Basically I needed to inject the corresponding model in the service constructor to be able to call the 'toObject' function with 'options' and 'populate'.基本上我需要在服务构造函数中注入相应的 model 才能调用带有“选项”和“填充”的“toObject”function。 Finally I need to use the obtained object to build a new instance of 'Desk' to make sure that class validation functions are applied correctly to my endpoints.最后,我需要使用获得的 object 来构建一个新的“Desk”实例,以确保 class 验证函数正确应用于我的端点。 Hope this will help someone and that maybe someone can suggest a more elegant solution.希望这会对某人有所帮助,也许有人可以提出更优雅的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM