Search code examples
javascripttypescriptpromisegraphqltypeorm

Iterating over nested array of objects that is defined as a Promise<Object[]>


I am using typeORM to declare data models.

It looks something like this:

@ObjectType()
@Entity("ParentObject")
@Index(['id'], { unique: true })
export class ParentObject {
  @Field({nullable: true})
  @PrimaryGeneratedColumn("uuid")
  uuid: string; 

  @Field(type => [NestedObject], {nullable: true})
  @OneToMany(type => NestedObject, nestedObject=> nestedObject.parentObject)
  nestedObjects: Promise<NestedObject[]>;

  @Column({
     nullable: true,
     type: 'timestamp'
  })
  @Field(() => GraphQLISODateTime, {nullable: true})
  @CreateDateColumn()
  createdDate: Date;

    }

The NestedObject array contains objects that are pulled alongside the ParentObject. They are a Promise because an asynchronous call is made by TypeORM to also pull them from another database table, referenced by the ID.

When I make a GraphQL call to the server, it returns ParentObject's as an array and I'm able to iterate over each one with code like this:

let data = await this.service.getParentObject(first, offset);

data = data.map((parentObject: ParentObject) => {
    return ParentObject.someFunction(parentObject);
});

return data;

I am able to modify values etc.

But my issue is to be able to iterate over the nestedObject's within the ParentObject. Given that they are declared as Promise<NestedObject[]>, it's not a standard Array and contains no function such as map or push.

So I would use code like this:

let data = await this.service.getParentObject(first, offset);

data = data.map((parentObject: ParentObject) => {
   let nestedObjects = parentObject.nestedObjects;
    nestedObjects.map(nestedObject=> {
        // some operations
    })
    return ParentObject.someFunction(parentObject);
});

return data;

I get the Typescript error:

Property 'map' does not exist on type 'Promise<NestedObject[]>'

Which leaves me unable to iterate over this nested array of objects, as it's not a simple array but rather a promise of a nested array of Objects. I am not sure how to proceed with this issue.

Any help would be greatly appreciated, thank you.


Solution

  • Just await the Promise, then you can access and manipulate the array like normal.

    data = data.map(async (parentObject: ParentObject) => {
        const resolvedPromise = await parentObject.nestedObjects
        parentObject.nestedObjects = resolvedPromise.map(nestedObject=> {
            // some operations
        })
        ...
    });
    

    Note that because the function we pass to data.map is now async, data.map will now return an array of Promises. This is perfectly fine since you can return that inside your resolver and GraphQL will handle it appropriately. However, if for some reason you need to manipulate the data variable before returning it, you'll need to await it as well. To await an array of Promises, though, you'd use Promise.all:

    data = await Promise.all(data.map(async () => {...}))