Home > Blockchain >  Loopback-next ReferenceMany Unable to find _id
Loopback-next ReferenceMany Unable to find _id

Time:08-09

I have user Model, which reference to ListedStocks,

@referencesMany(
    () => ListedStocks,
    {},
    {
      mongodb: {dataType: 'ObjectId'},
    },
  )
  stockIds?: string[];

But when i try to Create a user and pass an Array of Stocks _id, it gives me an error.

Error: Entity not found: ListedStocks with id "constraint {\"_id\":[\"62eeb4b42b59f883f02f381b\"]}"

When i tried To Debug this, I saw this Query.

loopback:connector:mongodb all ListedStocks { where: { _id: [ '62eeb4b42b59f883f02f381b' ] } } null []

shouldn't where : {_id: []} be where: {_id: {$in: []}}

Or am i missing something?

CodePudding user response:

The Issue was in the constraint created by the createReferencesManyAccessor

The constraint const constraint: any = {[primaryKey]: foreignKeyValue}; should have been constraint = {[primaryKey]: {inq:foreignKeyValue}};

Complete Fix is Below.

NOTE: This fix is specifically for the MongoDB, not sure if this breaks SQL Based Repos

export class TempReferencesManyRepository<
  TargetEntity extends Entity,
  TargetIds,
  TargetRepository extends EntityCrudRepository<TargetEntity, TargetIds>,
  > implements ReferencesManyRepository<TargetEntity>
{
  /**
   * Constructor of DefaultReferencesManyEntityCrudRepository
   * @param getTargetRepository - the getter of the related target model repository instance
   * @param constraint - the key value pair representing foreign key name to constrain
   * @param foreignKeyValue - PrimaryKey for Constraint
   * the target repository instance
   */
  constructor(
    public getTargetRepository: Getter<TargetRepository>,
    public constraint: DataObject<TargetEntity>,
    protected foreignKeyValue: any,
  ) {}

  async get(options?: Options): Promise<TargetEntity> {
    const targetRepo = await this.getTargetRepository();
    const result = await targetRepo.find(
      constrainFilter(undefined, this.constraint),
      options,
    );
    let expectedLength = 1;
    if(Array.isArray(this.foreignKeyValue)){
      expectedLength = this.foreignKeyValue.length;
    }
    if (result.length !== expectedLength) {
      // We don't have a direct access to the foreign key value here :(
      const id = 'constraint '   JSON.stringify(this.constraint);
      throw new EntityNotFoundError(targetRepo.entityClass, id);
    }
    console.log("RESULT: ",result);
    return result[0];
  }
}
export function createReferencesManyAccessor<
  Target extends Entity,
  TargetIds,
  Source extends Entity,
  SourceId,
  >(
  referencesManyMetadata: ReferencesManyDefinition,
  targetRepoGetter: Getter<EntityCrudRepository<Target, TargetIds>>,
  sourceRepository: EntityCrudRepository<Source, SourceId>,
): ReferencesManyAccessor<Target, SourceId> {
  const meta = resolveReferencesManyMetadata(referencesManyMetadata);
  debug('Resolved ReferencesMany relation metadata: %o', meta);
  const result: ReferencesManyAccessor<Target, SourceId> =
    async function getTargetInstancesOfReferencesMany(sourceId: SourceId) {
      const foreignKey = meta.keyFrom;
      const primaryKey = meta.keyTo;
      const sourceModel = await sourceRepository.findById(sourceId);
      const foreignKeyValue = sourceModel[foreignKey as keyof Source];
      // workaround to check referential integrity.
      // should be removed once the memory connector ref integrity is done
      // GH issue: https://github.com/loopbackio/loopback-next/issues/2333
      if (!foreignKeyValue) {
        return undefined as unknown as Target;
      }
      //FIXME: This is MONGODB Specific Fix, MIGHT BROKE in SQL.
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      let constraint: any = {[primaryKey]: foreignKeyValue};
      if(Array.isArray(foreignKeyValue)){
        constraint = {[primaryKey]: {inq: foreignKeyValue}};
      }
      const constrainedRepo = new TempReferencesManyRepository(
        targetRepoGetter,
        constraint as DataObject<Target>,
        foreignKeyValue
      );
      return constrainedRepo.get();
    };

  result.inclusionResolver = createReferencesManyInclusionResolver(
    meta,
    targetRepoGetter,
  );
  return result;
}

export default class ReferenceManyCurdRepository<
    T extends Entity,
    ID,
    Relations extends object = {}
  > extends DefaultCrudRepository<T, ID, Relations>{
  protected createReferencesManyAccessorFor<Target extends Entity, TargetId>(
    relationName: string,
    targetRepoGetter: Getter<EntityCrudRepository<Target, TargetId>>,
  ): ReferencesManyAccessor<Target, ID> {
    const meta = this.entityClass.definition.relations[relationName];
    return createReferencesManyAccessor<Target, TargetId, T, ID>(
      meta as ReferencesManyDefinition,
      targetRepoGetter,
      this,
    );
  }
}
  • Related