Search code examples
mikro-orm

mikro-orm Cascade.REMOVE, is it only for RDBMS?


I am using mikro-orm with MongoDB and trying to do a Cascade.REMOVE but i can not get it work.

Business entity:

@Entity({ collection: "business" })
export class BusinessModel implements BusinessEntity {
    @PrimaryKey()
    public _id!: ObjectId;

    @Property()
    public name!: string;

    @Property()
    public description!: string;

    @OneToMany({ entity: () => LocationModel, fk: "business", cascade: [Cascade.ALL] })
    public locations: Collection<LocationModel> = new Collection(this);
}

export interface BusinessModel extends IEntity<string> { }

Location entity:

@Entity({ collection: "location" })
export class LocationModel implements LocationEntity {
    @PrimaryKey()
    public _id!: ObjectId;

    @Property()
    public geometry!: GeometryEmbedded;

    @ManyToOne({ entity: () => BusinessModel})
    public business!: BusinessModel;

    public distance?: number;
}

export interface LocationModel extends IEntity<string> { }

Business Data:

_id: 5cac818273243d1439866227
name: "Prueba"
description: "Prueba eliminacion"

Location Data:

_id: 5cac9807179e380df8e43b6c
geometry: Object
business: 5cac818273243d1439866227

_id: 5cacc941c55fbb0854f86939
geometry: Object
business: 5cac818273243d1439866227

And the code:

export default class BusinessData {
    private businessRepository: EntityRepository<BusinessModel>;

    public constructor(@inject(OrmClient) ormClient: OrmClient) {
        this.businessRepository = ormClient.em.getRepository(BusinessModel);
    }

    public async delete(id: string): Promise<number> {
        return await this.businessRepository.remove(id);
    }
}

The "business" is correctly removed but all related "locations" continue there.

The log only show:

[query-logger] db.getCollection("business").deleteMany() [took 0 ms]


Solution

  • Cascades work on application level, so for all drivers, including mongo.

    The problem here is that you are removing the Business entity by id. You need to remove it by reference - provide the entity and be sure you have the collection populated, otherwise ORM does not know what entities to cascade remove.

    Try it like this:

    export default class BusinessData {
      public async delete(id: string): Promise<number> {
        const business = await this.businessRepository.findOne(id, ['locations'])
        return await this.businessRepository.remove(business);
      }
    }
    

    Your approach with removing by id would work only if the entity was already loaded in identity map (aka managed by EM), including the locations collection.