Upload lên GridFS trong NestJS: cả file nằm trong RAM trước đã

Trong dkhoa-dev/nestjs-multer-gridfs, download thì stream, còn upload lại buffer cả file trong bộ nhớ. Chỗ đó nằm ở đâu và nên sửa thế nào.

Phan Minh Đăng Khoa
3 phút đọcAI viết · AI soát
Mục lục

dkhoa-dev/nestjs-multer-gridfs là repo công khai, một service NestJS nhỏ lưu file vào MongoDB GridFS. Có bốn route: POST /files/upload, GET /files, GET /files/:id và DELETE /files/:id. Bài này soi một chỗ không đều tay trong code: download thì stream, upload thì không.

Download: stream thẳng ra client

downloadFile gọi bucket.openDownloadStream(id), controller thì stream.pipe(res). Chunk nào từ MongoDB về là đẩy ra client luôn. Server không lúc nào giữ cả file.

Upload: buffer cả file trong bộ nhớ

Route upload dùng FileInterceptor('file') và không truyền option nào. README của Multer ghi: bỏ trống object options thì Multer giữ file trong bộ nhớ, không ghi xuống đĩa. Nghĩa là file.buffer đã chứa nguyên file trước khi GridFS nhận được byte nào.

Sau đó uploadFile bọc buffer này thành stream rồi pipe vào bucket.openUploadStream:

const bufferStream = require('stream').Readable.from(file.buffer);
bufferStream.pipe(uploadStream)
Chỗ file nằm trong bộ nhớ trước khi GridFS nhận.

GridFS mặc định cắt file thành chunk 255 * 1024 byte (chunkSizeBytes trong driver mongodb, lockfile ghi bản 6.12.0). Chia chunk thì không sao. Cái đáng lo là buffer đã có sẵn từ trước bước đó.

Multer cũng không giới hạn kích thước file nếu không truyền limits. README liệt kê fileSize với giá trị mặc định là Infinity. Repo này không truyền, nên mỗi lần upload một file lớn là process phải giữ trong bộ nhớ ít nhất đúng bằng dung lượng file đó.

Thêm hai chỗ nhỏ

  • README ghi MongoDB chạy cổng 27017, nhưng src/app.module.ts lại kết nối tới mongodb://localhost:62553/fs. Hai chỗ không khớp nhau.
  • downloadFile và deleteFile bọc hết trong try/catch rồi ném NotFoundException. Id sai định dạng hay lỗi thật cũng đều trả về 404.

Bài học

  • Thấy pipe chưa chắc đã là stream thật, phía trước vẫn có thể là một buffer. Phải xem byte lấy từ đâu ra.
  • Route upload nào dùng Multer cũng nên đặt limits.fileSize, bản demo cũng vậy.
  • Muốn bộ nhớ không phình theo cỡ file thì đưa thẳng stream multipart vào GridFS, đừng đi qua file.buffer. Repo này chưa làm chỗ đó.
  • So README với code. Ở repo này hai bên lệch nhau về cổng database.
Phan Minh Đăng Khoa
Principal Engineer · AI, IoT và tự động hoá công nghiệp.
Bài sau →Point-adjusted F1 tô hồng detector phát hiện bất thường (TSB-AD)