Skip to content

useMongocampBucket

Detection and file operations for GridFS bucket collections. Powers the upload/download support in MongocampCollectionData, the bucket-level actions in MongocampCollections, and the file-level browsing/management in MongocampBucketFiles.

ts
const {
  isBucketCollection,     // (collectionName: string) => boolean
  bucketNameFor,          // (collectionName: string) => string
  fileIdForRow,           // (collectionName: string, row: Record<string, unknown>) => string | undefined
  downloadingFileIds,     // Ref<Set<string>>
  uploading,              // Ref<boolean>
  downloadFile,           // (collectionName: string, fileId: string) => Promise<void>
  uploadFile,             // (collectionName: string, file: File) => Promise<boolean>
  bucketActionInFlight,   // Ref<Set<string>> — bucket names with a clear/delete in progress
  fileActionInFlight,     // Ref<Set<string>> — file ids with a delete/rename in progress
  listFiles,              // (bucketName: string, options?: ListFilesOptions) => Promise<ListFilesResult>
  deleteFile,             // (bucketName: string, fileId: string) => Promise<boolean>
  updateFileInformation,  // (bucketName: string, fileId: string, options: UpdateFileInformationOptions) => Promise<boolean>
  listBuckets,            // () => Promise<string[]>
  getBucketInfo,          // (bucketName: string) => Promise<BucketInformation>
  clearBucket,            // (bucketName: string) => Promise<boolean>
  deleteBucket,           // (bucketName: string) => Promise<boolean>
} = useMongocampBucket()

Background: a bucket is two collections

Uploading a file through a GridFS bucket (fileApi.insertFile) creates/uses two real Mongo collections: <bucketName>.files (one document per file, with filename/length/metadata) and <bucketName>.chunks (the binary chunks). Both appear in collectionApi.listCollections() like any other collection.

Detecting and naming buckets

ts
isBucketCollection('images.files')   // true
isBucketCollection('images.chunks')  // true
isBucketCollection('customers')      // false

bucketNameFor('images.files')        // 'images'
bucketNameFor('images.chunks')       // 'images'

Resolving a file id from a row

Which field holds the file id depends on which half of the bucket you're looking at:

  • On a .files row, the file id is the row's _id.
  • On a .chunks row, the file id is the row's files_id (its own _id is the chunk id).
ts
fileIdForRow('images.files', { _id: { $oid: 'abc123' } })          // 'abc123'
fileIdForRow('images.chunks', { files_id: 'abc123', _id: 'c1' })   // 'abc123'

Both _id and files_id may arrive as a plain string or as extended-JSON { $oid: '...' }fileIdForRow unwraps either shape.

Downloading a file

ts
await downloadFile('images.files', fileId)

Fetches fileApi.getFileInformation (for the real filename) and fileApi.getFile (the blob), then triggers a browser download. Falls back to the raw file id as the download name if no filename is known. Tracks in-flight downloads in downloadingFileIds (add a :loading="downloadingFileIds.has(fileId)" binding on your button) and shows an error toast on failure.

Uploading a file

ts
const success = await uploadFile('images.files', file) // file: File
if (success) await fetchDocuments() // refresh the table

Uploads via fileApi.insertFile, targeting the bucket regardless of whether collectionName was the .files or .chunks half. Tracks the in-flight upload in uploading and shows a success/error toast; returns true/false so the caller knows whether to refresh.

Listing, deleting, and renaming individual files

Unlike downloadFile/uploadFile (which work per-file but need a resolved id from a raw document row), these operate directly against a bucket name and return/accept the clean, typed FileInformation shape (id, filename, length, chunkSize, uploadDate, metadata) — no extended-JSON unwrapping needed:

ts
const { files, total } = await listFiles('images', {
  filter: 'filename:*.png',   // Lucene filter string, same convention as useMongocampQuery
  sort: '-uploadDate',
  page: 1,
  rowsPerPage: 20,
})

const deleted = await deleteFile('images', fileId)
const renamed = await updateFileInformation('images', fileId, { filename: 'new-name.png', metadata: { owner: 'alice' } })

listFiles reads the total row count from the x-pagination-count-rows response header (same convention MongocampCollectionData uses for documents), returning 0 if the header is absent. deleteFile/updateFileInformation follow the same loading-state/toast/boolean-return convention as every other mutation here — both track in-flight file ids via fileActionInFlight (bind :loading="fileActionInFlight.has(fileId)"), show a success/error toast, and return a boolean so the caller knows whether to refresh.

Bucket-level operations

Unlike the per-file methods above, these operate on the whole bucket (both its .files and .chunks collections at once) via the raw bucketApi, not fileApi:

ts
const buckets = await listBuckets()                 // ['images', 'avatars', ...]
const info = await getBucketInfo('images')           // { name, files, size, avgObjectSize }
const cleared = await clearBucket('images')          // deletes every file in the bucket, keeps the bucket
const deleted = await deleteBucket('images')         // drops both images.files and images.chunks entirely

clearBucket/deleteBucket follow the same convention as uploadFile: they track their own loading state (bucketActionInFlight, keyed by bucket name — bind :loading="bucketActionInFlight.has(bucketName)"), show a success/error toast, and return a boolean so the caller knows whether to refresh.

Released under the MIT License.