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?
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,
);
}
}