TypeORM中MongoDB的findOneAndUpdate(upsert:true)未生成时间字段的解决方法
问题
在启用自动生成createdAt和updatedAt字段的TypeORM MongoDB仓库中,使用findOneAndUpdate并设置upsert:true时,这两个字段始终未被插入或更新。请问这种情况是否正常?该如何解决?需求是用最少的数据库请求实现「查询到则更新,未查询到则创建」的逻辑。
代码示例
import { ObjectID } from 'mongodb'; import { container, instanceCachingFactory } from 'tsyringe'; import { Column, Entity, EntityRepository, getCustomRepository, MongoRepository, } from 'typeorm'; import { CreateDateColumn, ObjectIdColumn, UpdateDateColumn } from 'typeorm'; export abstract class TypeOrmAbstractEntity { @ObjectIdColumn() _id: ObjectID; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; get id() { return this._id.toHexString(); } } @Entity('subscriptions') export class Subscription extends TypeOrmAbstractEntity { @Column({ nullable: false }) subscriptionID: string; @Column({ nullable: false }) customerID: string; } @EntityRepository(Subscription) export class SubscriptionRepository extends MongoRepository<Subscription> {} container.register<SubscriptionRepository>(SubscriptionRepository, { useFactory: instanceCachingFactory(() => getCustomRepository(SubscriptionRepository) ), }); // ... const stripeSubscriptionRepository = container.resolve(SubscriptionRepository); subscriptionRepository.findOneAndUpdate( { customerID }, { $set: { subscriptionID: subscription.id, customerID: customerID, }, }, { upsert: true } );
解答
这种情况是正常的。TypeORM的CreateDateColumn和UpdateDateColumn自动填充逻辑,仅在调用TypeORM封装的实体操作方法(如save()、insert())时才会触发。而findOneAndUpdate是直接调用MongoDB原生操作,TypeORM不会为这类原生方法自动注入时间字段的填充逻辑。
解决方案
1. 手动在更新管道中维护时间字段(最少请求)
通过MongoDB的$set和$setOnInsert操作符,分别处理更新和插入场景下的时间字段:
subscriptionRepository.findOneAndUpdate( { customerID }, { $set: { subscriptionID: subscription.id, customerID: customerID, updatedAt: new Date() // 更新时设置当前时间 }, $setOnInsert: { // 仅在插入新文档时生效 createdAt: new Date() } }, { upsert: true } );
$setOnInsert仅在upsert触发插入操作时执行,保证createdAt只在创建时赋值$set中的updatedAt会在更新和插入时都生效,确保新创建的文档也有正确的updatedAt值
2. 使用TypeORM的save()方法(更符合ORM设计)
如果可以接受一次额外的查询请求,save()方法会自动触发时间字段填充,同时内部处理「存在则更新,不存在则插入」的逻辑:
let subscriptionEntity = await subscriptionRepository.findOne({ customerID }); if (!subscriptionEntity) { subscriptionEntity = subscriptionRepository.create({ customerID, subscriptionID: subscription.id }); } else { subscriptionEntity.subscriptionID = subscription.id; } await subscriptionRepository.save(subscriptionEntity);
这种方式代码更简洁,符合TypeORM的抽象设计,也更易维护。
内容的提问来源于stack exchange,提问作者A.D.V. - F
相关产品推荐
相关产品推荐

