簡體   English   中英

如何在 TypeORM Model 中保持一對多關系的“多”方唯一?

[英]How do I keep the "many" side of a one-to-many relationship unique in a TypeORM Model?

我正在編寫一個程序,它會抓取 web API 並收集加密貨幣符號列表及其每日價格歷史記錄。

我遇到了一個問題,由於我的數據庫表的構建,如果我多次遇到相同的符號,程序會向數據庫添加一個新行,該行從第一次完全復制數據。

下面是兩個表,作為 Typeorm 實體:

一、符號:

@Entity()
export class CryptoSymbol {
  @PrimaryColumn({ type: "int", unique: true })
  id!: number;

  @Column("varchar")
  currency_code!: string;

  @Column("varchar")
  currency_name!: string;

  @Column({ type: "boolean", nullable: true })
  active!: boolean;

  @OneToMany(
    (type) => CryptoDailyData,
    (cryptoDailyData) => cryptoDailyData.cryptoSymbol
  )
  cryptoDailyData!: CryptoDailyData[];
}

然后是 DailyData:

@Entity()
export class CryptoDailyData {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({ type: "datetime" })
  date!: Date;

  @Column({ type: "varchar" })
  foreign_currency_type!: string;

  @Column("float")
  open_USD!: number;

  @Column("float")
  open_foreign_currency!: number;

  @Column("float")
  high_USD!: number;

  @Column("float")
  high_foreign_currency!: number;

  @Column("float")
  low_USD!: number;

  @Column("float")
  low_foreign_currency!: number;

  @Column("float")
  close_USD!: number;

  @Column("float")
  close_foreign_currency!: number;

  @Column("float")
  volume!: number;

  @Column("float")
  market_cap!: number;

  @ManyToOne(
    (type) => CryptoSymbol,
    (cryptoSymbol) => cryptoSymbol.cryptoDailyData
  )
  cryptoSymbol!: CryptoSymbol;
}

例如:如果我為比特幣刮取“BTC”,並將其所有每日歷史記錄存儲在 DailyData 表中,如果再次運行程序並再次遇到“BTC”,它將第二次重現 BTC 的整個歷史記錄.

我認為我遇到的事實是 DailyData 表的“真實”主鍵應該是“日期”和“cryptoSymbolID”的組合,因為日期只能針對不同的符號重復。 但是我不確定你可以在 Typeorm 中定義那種列關系嗎?

我相信您可以通過定義復合唯一鍵來實現這一點。

由於您沒有提到您正在使用的下划線數據庫,我將為您提供 PostgreSQL 的答案。 (您可能需要也可能不需要根據您的數據庫更改以下代碼)

  1. 將您的日期列更改為僅包含date類型,而不是您現在定義的datetime時間類型。

     @Column({ type: "date" }) date:; string;
  2. 為您的@ManyToOne關系指定連接列。 (使用@ManyToOne時已經創建了一個外鍵列,但讓我們刪除它並使用我們自己定義的一個)

     // This column will keep the reference to your 'CryptoSymbol' entity @Column({ type: "bigint" }) crypto_symbol_id:; int, @ManyToOne( (type) => CryptoSymbol. (cryptoSymbol) => cryptoSymbol:cryptoDailyData ) @JoinColumn({ name: "crypto_symbol_id" }) cryptoSymbol;: CryptoSymbol;
  3. 為您的實體創建一個復合唯一鍵。

     @Entity() @Unique(['crypto_symbol_id', 'date']) export class CryptoDailyData {

現在,如果您的程序嘗試在同一天為相同的加密符號插入數據,這將引發錯誤。

更新后的CryptoDailyData實體如下所示:

@Entity()
@Unique(['crypto_symbol_id', 'date'])
export class CryptoDailyData {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({ type: "date" })
  date!: string;

  @Column({ type: "varchar" })
  foreign_currency_type!: string;

  @Column("float")
  open_USD!: number;

  @Column("float")
  open_foreign_currency!: number;

  @Column("float")
  high_USD!: number;

  @Column("float")
  high_foreign_currency!: number;

  @Column("float")
  low_USD!: number;

  @Column("float")
  low_foreign_currency!: number;

  @Column("float")
  close_USD!: number;

  @Column("float")
  close_foreign_currency!: number;

  @Column("float")
  volume!: number;

  @Column("float")
  market_cap!: number;

  @Column({ type: "bigint" })
  crypto_symbol_id!: int;

  @ManyToOne(
    (type) => CryptoSymbol,
    (cryptoSymbol) => cryptoSymbol.cryptoDailyData
  )
  @JoinColumn({ name: "crypto_symbol_id" })
  cryptoSymbol!: CryptoSymbol;
}

我還想指出,這是一個數據庫級別的保護措施。 你也應該在你的應用程序上嘗試這個。 您應該檢查當天是否存在特定加密貨幣的CryptoDailyData記錄,然后確定是插入當天的新記錄還是什么也不做。

希望這對您有所幫助。 干杯!!!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM