GridFS
Instance and Model helpers store and read MongoDB GridFS files. The published npm package is still 3.4.0; this API is staged in the source after that release and is not a published 3.5.0 package.
GridFS is a client convention on ordinary collections (<bucket>.files and <bucket>.chunks). It does not require a Search or Vector Search deployment. Integration coverage uses mongodb-memory-server 7.0.37. The formal server matrix remains MongoDB 7.x and 8.x. Older servers, including 4.x, are unverified.
Open a bucket
bucketName defaults to fs. An empty string is rejected. chunkSizeBytes defaults to 261120 (255 KiB) and must be a positive integer.
msq.gridfs() uses the runtime connection unless pool names a configured pool. A named pool uses that pool's client and client.db(db). db defaults to the runtime database. model.gridfs() always uses the Model poolName and dbName; it does not accept pool or db.
Calling either method before connect() throws NOT_CONNECTED.
Files API
idOrName is an ObjectId or { filename, revision? }. revision follows the driver: 0 is the oldest file with that name, and -1 (the default) is the newest. download({ filename }) therefore returns the latest file with that name.
ifExists and sha256
upload defaults to ifExists: 'error'.
- When
sha256is set, the conflict key ismetadata.sha256. The digest must be 64 lowercase hex characters.BufferandUint8Arraypayloads are hashed before any GridFS write. A mismatch throwsGRIDFS_INTEGRITY_MISMATCHand leaves no visible file. - A
Readablepassed withsha256is buffered completely, then hashed, before any write. Large files should use the resumable API instead. skipwithsha256returns the newest visible file with that digest.skipwithoutsha256returns the newest visible file with the same filename.duplicatealways creates another file.uploadStreamstoressha256in metadata only. It does not check the bytes and it does not acceptifExists.
metadata.sha256 written by these helpers overwrites a caller-supplied metadata.sha256. A provided contentType is stored as metadata.contentType and overwrites a caller-supplied value of that field. FileInfo.contentType returns it. An older file that still has a top-level contentType is returned the same way.
Ranges
downloadStream ranges use an inclusive start and an exclusive end. Omitted start means 0. Omitted end means the file length. A legal range satisfies 0 <= start < end <= length. Anything else, including start === end and start === length, emits GRIDFS_RANGE_INVALID. When the failure depends on the file length, details[0].length is that length. Shape errors that can be rejected before a lookup omit length. download() reads the whole file and does not accept a range.
Resumable upload
Phase 1 resumable upload keeps a pending session in <bucket>.uploads until finalize. The file stays invisible until finalizeResumableUpload succeeds. uploadId is the future files._id.
beginResumableUpload requires length and sha256. An id that already exists in files or uploads throws GRIDFS_FILE_EXISTS.
Chunk bytes must follow the session size:
- Every chunk except the last has length
chunkSizeBytes. - The last chunk has length
length % chunkSizeBytes, orchunkSizeByteswhen the length divides evenly. - A payload that does not split into those sizes throws
INVALID_ARGUMENT. The whole payload is checked before any chunk is inserted.
appendChunks is addressed by fromChunk:
fromChunkpast the contiguous prefix throwsGRIDFS_RESUME_MISMATCHwithexpectedNextChunk.- Replaying already stored chunks with the same bytes is idempotent and does not move
nextChunkbackward. - Replaying an earlier chunk with different bytes throws
GRIDFS_RESUME_MISMATCH. - A payload that contains any new chunk must start at
nextChunk. Starting earlier throwsGRIDFS_RESUME_MISMATCHand writes nothing. - A duplicate
{ files_id, n }insert is accepted only when the stored bytes match.
finalizeResumableUpload requires a contiguous prefix, a total length equal to the session length, and a sha256 equal to the session digest. It then inserts the files document, sets metadata.sha256, and deletes the session. Missing chunk indexes throw GRIDFS_UPLOAD_INCOMPLETE with details[0].missingChunks. A bad digest or a chunk of the wrong size throws GRIDFS_INTEGRITY_MISMATCH. The files document is not inserted in those cases.
abortResumableUpload deletes the session and, when no files document is visible, that upload's chunks. A missing or already aborted session resolves. Aborting an id that already has a visible file does not delete that file's chunks.
<bucket>.uploads has a TTL index on createdAt with expireAfterSeconds: 604800 (7 days). The TTL deletes upload session documents only. It does not delete chunks. Abort or finalize sessions that are no longer needed.
Indexes
upload, uploadStream (before the driver stream is opened), beginResumableUpload, and ensureIndexes create:
Reads do not create indexes. A write rejected by writePathPolicy does not create them either.
writePathPolicy
GridFS writes are category gridfs. The namespace is <bucket>.files, matched with the usual order: instance id, pool:db.collection, db.collection, collection name, then default.
inherit does not follow the management rule. Management inherit still allows Model management and blocks direct management. GridFS inherit under model-only blocks both sources. model.gridfs().drop() stays a management operation, so Model drop remains allowed under model-only while msq.gridfs().drop() is blocked.
A blocked call throws INVALID_OPERATION before any GridFS write. details[0] includes category: 'gridfs' (or 'management' for drop) and reason: 'WRITE_PATH_POLICY'. onViolation: 'warn' logs that detail and allows the call. getFile, findFiles, download, and downloadStream are not governed.
Errors
downloadStream delivers GRIDFS_FILE_NOT_FOUND and GRIDFS_RANGE_INVALID on the stream. The method itself does not throw those errors.