iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
Mobile Development

30天 使用chatGPT輔助學習APP完成接案任務委託系列 第 27

[Day27] NestJS 與 MongoDB 報告系統實作:資料庫模型設計

  • 分享至 

  • xImage
  •  

今天我們要進行的是設計 報告(Report) 的資料模型與資料庫結構。接下來的部分會介紹 schemas,特別針對 CHP555 報告的資料結構。因為將來可能會有其他類型的報告,我們會將這些報告模型分開管理。

Schemas

資料夾 /reports/schemas 中,我們會建立一個名為 CHP555Report 的模型。將來若有其他類型的報告,它們也可以被放在同一個結構下,保持清晰且擴展性佳。

首先,我們會在 schemas 資料夾下建立 chp555Report.schema.ts。這裡將會定義報告的核心結構,也就是報表上的欄位與對應的資料類型。

定義參與者:parties 欄位

在設計報表時,會有多個參與者,像是目擊者或相關人員。每個參與者會有獨立的資料表來存儲具體的資訊。通過下方的設計,我們在報告模型中引用了參與者的 ID,確保資料之間的關聯性。

  @Prop([{ type: SchemaTypes.ObjectId, ref: 'Party' }])
  parties: Types.ObjectId[];

這段程式碼定義了 parties 欄位,它會連接到另一個 Party 模型,使用 ObjectId 類型來建立資料庫中的關聯。

Chp555Report 模型

接下來是 Chp555Report 的完整模型設計。這個模型包含了報告中所有關鍵的欄位,並根據需求指定了每個欄位的類型與是否必填。

import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document, SchemaTypes, Types } from 'mongoose';

import {
  SpecialConditionEnum,
  NunmberEunm,
} from '../../../const/eumns/chp555Report';

import { Location } from './location.schema';

@Schema({ timestamps: true, minimize: false })
export class Chp555Report extends Document {
  @Prop({ required: true })
  userId: string;

  @Prop({ required: true })
  username: string;

  @Prop({ required: false, enum: SpecialConditionEnum, type: Array })
  specialConditions: SpecialConditionEnum[];

  // 受傷人數
  @Prop({ required: false, enum: NunmberEunm, type: String })
  numberInjured: NunmberEunm;

  // 死亡人數
  @Prop({ required: false, enum: NunmberEunm, type: String })
  numberKilled: NunmberEunm;

  // 肇事逃逸
  @Prop()
  isFelony: boolean;

  // 輕罪
  @Prop()
  isMisdemeanor: boolean;

  @Prop()
  city: string;

  @Prop()
  judicialDistrict: string;

  @Prop()
  county: string;

  @Prop()
  reportingDistrict: string;

  @Prop()
  beat: string;

  // 星期幾
  @Prop()
  dayOfWeek: string;

  // 違規停車
  @Prop()
  isTwoWay: boolean;

  // 報告號碼
  @Prop({ required: false })
  reportNumber: string;

  @Prop([{ type: SchemaTypes.ObjectId, ref: 'Party' }])
  partyies: Types.ObjectId[];

  @Prop(Location)
  location: Location;
}

const Chp555ReportSchema = SchemaFactory.createForClass(Chp555Report);

Chp555ReportSchema.set('toJSON', {
  virtuals: true,
  versionKey: false,
  transform: (doc, ret) => {
    ret.id = ret._id;
    delete ret._id;
    return ret;
  },
});

export { Chp555ReportSchema };

地點資訊:location 外鍵

報告中另一個重要部分是事件的發生地點。我們將這些地點資訊設計成獨立的 Location 模型,並在主模型中引用。

...
import { Location } from './location.schema';

@Schema({ timestamps: true, minimize: false })
export class Chp555Report extends Document {
....

  @Prop(Location)
  location: Location;
}
 ...

詳細程式碼如下:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Location {
  @Prop()
  crashOccurredOn: string;

  // GPS座標
  @Prop({
    type: {
      latitude: { type: String },
      longitude: { type: String },
    },
  })
  gpsCoordinates: {
    latitude: string;
    longitude: string;
  };

  @Prop()
  date: Date;

  @Prop()
  time: number;

  @Prop()
  stateHwyReel: boolean;

  @Prop()
  NCIC: string;

  @Prop()
  officerId: string;

  @Prop()
  photographsBy: string;
}

export const LocationSchema = SchemaFactory.createForClass(Location);

[!TIP] 回傳
下面程式碼可以讓回傳的 _id 變成 id

Chp555ReportSchema.set('toJSON', {
  virtuals: true,
  versionKey: false,
  transform: (doc, ret) => {
    ret.id = ret._id;
    delete ret._id;
    return ret;
  },
}); 

Party 參與者 模型

除了報告的核心資訊之外,參與者(如駕駛、目擊者等)也是報告的重要組成部分。接下來我們來看 Party 模型的設計,這個模型儲存了參與者的身份、角色以及相關細節。

import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document, SchemaTypes, Types } from 'mongoose';

import { Role } from '../../../../const/eumns/chp555Report';
import { DriverLicense } from './driverLicense.schema';

@Schema({ timestamps: true, minimize: false })
export class Party extends Document {
  // 連結報告id
  @Prop({ type: SchemaTypes.ObjectId, ref: 'Chp555Report' })
  reportId: Types.ObjectId;

  // 順序 , 必填
  @Prop({ required: true })
  order: number;

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

  // 角色
  @Prop({ type: String, enum: Role })
  role: Role;

  @Prop(DriverLicense)
  driverLicense: DriverLicense;

  toJSON() {
    const obj = this.toObject();
    obj.id = obj._id;
    delete obj._id;
    delete obj.__v;
    return obj;
  }
}

export const PartySchema = SchemaFactory.createForClass(Party);

駕照資訊:driverLicense

駕駛的詳細資料存儲於 driverLicense 模型中,這裡包含了駕照號碼、車輛資訊等。該模型可以和 Party 參與者模型進行關聯,將駕駛的資料以結構化的方式儲存。

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class DriverLicense {
  @Prop({})
  licenseNumber: string;

  // 角色選擇
  @Prop({})
  driver: boolean;

  @Prop({})
  ped: boolean;

  @Prop({})
  parkedVehCheckBox: boolean;

  @Prop({})
  bicycleCheckBox: boolean;

  @Prop({})
  otherCheckBox: boolean;

  @Prop({})
  operatorCheckBox: boolean;

  @Prop({})
  state: string;

  @Prop({})
  class: string;

  @Prop({})
  airBag: string;

  @Prop({})
  safetyEquipment: string;

  @Prop({})
  name: string;

  @Prop({})
  streetAddress: string;

  @Prop({})
  citystatezip: string;

  @Prop({})
  zip: string;

  @Prop({})
  sex: string;

  @Prop({})
  hair: string;

  @Prop({})
  eyes: string;

  @Prop({})
  weight: number;

  @Prop({})
  height: number;

  @Prop({})
  birthdate: string;

  @Prop({})
  race: number;

  @Prop({})
  homePhoneAreaCode: string;

  @Prop({})
  homePhone: string;

  @Prop({})
  businessPhone: string;

  @Prop({})
  businessPhoneAreaCode: string;

  @Prop({})
  insuranceCarrier: string;

  @Prop({})
  policyNumber: string;

  @Prop({})
  streetOrHwy: string;

  @Prop({})
  lane: string;

  @Prop({})
  thruLanes: string;

  @Prop({})
  totalLanes: string;

  @Prop({})
  speedLimit: string;

  @Prop({})
  licensePhotoUrl: string;
}

export const DriverLicenseSchema = SchemaFactory.createForClass(DriverLicense);

行照

vehicel.schema.ts

import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document, SchemaTypes, Types } from 'mongoose';

@Schema({ timestamps: true, minimize: false })
export class Vehicel extends Document {
  @Prop({ required: true })
  userId: string;

  @Prop({ required: true })
  username: string;

  @Prop({ required: false })
  reportNumber: string;

  @Prop({ required: false })
  vehicleNumber: string;

  @Prop({ required: false })
  vehicleType: string;

  @Prop({ required: false })
  vehicleYear: string;

  @Prop({ required: false })
  vehicleMake: string;

  @Prop({ required: false })
  vehicleModel: string;

  @Prop({ required: false })
  vehicleColor: string;

  @Prop({ required: false })
  vehicleLicensePlate: string;

  @Prop({ required: false })
  vehicleLicenseState: string;

  @Prop({ required: false })
  vehicleVIN: string;

  @Prop({ required: false })
  vehicleRegistrationExpiration: string;

  @Prop({ required: false })
  vehicleInsuranceCompany: string;

  @Prop({ required: false })
  vehicleInsurancePolicyNumber: string;

  @Prop({ required: false })
  vehicleInsuranceExpiration: string;

  @Prop({ required: false })
  vehicleInsuranceAgent: string;

  @Prop({ required: false })
  vehicleInsuranceAgentPhone: string;

  @Prop({ required: false })
  vehicleInsuranceAgentEmail: string;

  @Prop({ required: false })
  vehicleInsuranceAgentFax: string;

  @Prop({ required: false })
  vehicleInsuranceAgentAddress: string;

  @Prop({ required: false })
  vehicleInsuranceAgentCity: string;

  @Prop({ required: false })
  vehicleInsuranceAgentState: string;

  @Prop({ required: false })
  vehicleInsuranceAgentZip: string;

  @Prop({ required: false })
  vehicleInsuranceAgentCountry: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicense: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseState: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseExpiration: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicensePhone: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseEmail: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseFax: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseAddress: string;

  @Prop({ required: false })
  vehicleInsuranceAgentLicenseCity: string;
}

資料結構目錄

/src
  ├── /auth
  ├── /const
  ├── /reports
  │   ├── chp555Report.controller.ts
  │   ├── /schemas
  │   │   ├── CHP555Report
  │   │   │   ├── chp555Report.schema.ts
  │   │   │   ├── location.schema.ts
  │   │   │   └── /Party
  │   │   │       ├── party.schema.ts
  │   │   │       ├── driverLicense.schema.ts
  │   │   │       └── vehicel.schema.ts
  ├── /service
  │   └── chp555Report.service.ts

結語

今天我們介紹了報告系統的資料庫模型與結構,未來這些資料會被應用於 CRUD 操作。下一篇文章,我們會展示如何基於這些模型進行 CRUD 操作,從建立到更新再到刪除資料,敬請期待!

#it鐵人


上一篇
[Day26] ERD 圖與使用者報告資料庫設計
下一篇
[Day28] Chp555 報告 next.js CRUD 實作
系列文
30天 使用chatGPT輔助學習APP完成接案任務委託30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言