Access to files in MongoDB GridFS with NestJS and GraphQL

Viewed 447

I'm working with NestJS with GraphQL and MongoDB. I'm trying store image files using GridFS using mongo-gridfs package.

Uploading images to database works fine, but how can I access to this files? I mean for example I want to get source path of this files and use it in my frontend

Here is my resolver and service:

// photo.resolver.ts

import { Resolver, Mutation, Query, Args } from '@nestjs/graphql';
import { GraphQLUpload, FileUpload } from 'graphql-upload';
import { Photo } from './dto/photo.dto';
import { PhotoService } from './services/photo.service';

@Resolver()
export class PhotoResolver {
  constructor(
    private readonly photoService: PhotoService
  ) {}

  @Query(() => ???, { nullable: true })
  async photo(@Args('id', { nullable: true }) id: string) {
    const photo = await this.photoService.findOne(id);
    return ???;
  }

  @Mutation(() => Photo)
  async uploadPhoto(@Args({name: 'file', type: () => GraphQLUpload}) file: FileUpload) {
    return await this.photoService.save(file);
  }
}
// photo.service.ts

import { Connection } from 'mongoose';
import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/mongoose';
import { FileUpload } from 'graphql-upload';
import { MongoGridFS } from 'mongo-gridfs';
import { Photo } from '../photo.interface';

@Injectable()
export class PhotoService {
  private fileModel: MongoGridFS;
  
  constructor(
    @InjectConnection() private readonly connection: Connection
  ) {
    this.fileModel = new MongoGridFS(this.connection.db as any, 'photo');
  }  

  async findOne(id: string) {
    return await this.fileModel.findById(id);
  }
  
  async save(file: FileUpload): Promise<Photo> {
    return await this.fileModel.writeFileStream(file.createReadStream(), {
      filename: file.filename,
      contentType: file.mimetype
    });
  }
}

I've tried two approached:

  1. I used downloadFile method from my photoModel, but it returns path to this file in my Temp directory in local disk.
// photo.service.ts
async findOne(id: string): Promise<string> {
  return await this.fileModel.downloadFile(id); // C:\...\AppData\Local\Temp\189450ef
}

// photo.resolver.ts
@Query(() => String, { nullable: true })
async photo(@Args('id', { nullable: true }) id: string) {
  return id && await this.photoService.findOne(id);
}

It works per se but it doesn't look to me as a proper solution. I'd prefer that source path should "lead" to my server.

  1. I used readFileStream method from my photoModel, which return filestream and added @Res() res to arguments in resolver.
// photo.service.ts
async findOne(id: string): Promise<GridFSBucketReadStream> {
  return await this.fileModel.readFileStream(id);
}

// photo.resolver.ts
@Query(() => Boolean)
async photo(@Args('id', { nullable: true }) id: string, @Res() res) {
  const photoStream = await this.photoService.findOne(id);
  photoStream.pipe(res);
  return true;
}

And now I've got such an error in terminal:

[Nest] 12408   - 10.07.2021, 13:02:25   [ExceptionsHandler] dest.on is not a function +27555ms
TypeError: dest.on is not a function
0 Answers
Related