.. _gridfs: ****** GridFS ****** .. default-domain:: mongodb .. contents:: On this page :local: :backlinks: none :depth: 1 :class: singlecol The driver provides a clean and simple interface to work with storage of chunked files in the database, also known as the pattern "GridFS". The API allows you to either work with Grid::File objects or with read and write streams. Creating a GridFS object ("Grid::FSBucket") =========================================== You can create a GridFS object by calling ``fs`` on a database, with optional arguments. ``fs`` returns a ``Grid::FSBucket`` object. The options that ``Grid::FSBucket`` supports are: .. list-table:: :header-rows: 1 :widths: 40 80 * - Option - Description * - ``:bucket_name`` - The name of the GridFS Bucket. Default is ``fs``. * - ``:fs_name`` - The name of the GridFS Bucket. Takes precedence over ``bucket_name``. Default is ``fs``. * - ``:chunk_size`` - Specifies the size of each file chunk in the database. * - ``:write_concern`` - The write concern to use when uploading files. Please see the :ref:`Write Concern ` section under CRUD operations for how to work with write concerns. * - ``:write`` - Deprecated. Same as ``:write_concern``. * - ``:read`` - The read preference to use when downloading files. For example, you can create a GridFS bucket object with a particular read preference: .. code-block:: ruby fs_bucket = database.fs( read: { mode: :secondary } ) Working with write streams ========================== To upload a file to GridFS using a write stream, you can either open a stream and write to it directly or write the entire contents of an ``IO`` object to GridFS all at once. To open an upload stream and write to it: .. code-block:: ruby File.open('/path/to/my-file.txt', 'r') do |file| fs_bucket.open_upload_stream('my-file.txt') do |stream| stream.write(file) end end To upload the entire contents of an IO object in one call: .. code-block:: ruby File.open('/path/to/my-file.txt', 'r') do |file| fs_bucket.upload_from_stream('my-file.txt', file) end Write streams support the following options: .. list-table:: :header-rows: 1 :widths: 40 80 * - Option - Description * - ``:chunk_size`` - Specifies the size of each file chunk in the database. * - ``:write_concern`` - The write concern to use when uploading files. Please see the :ref:`Write Concern ` section under CRUD operations for how to work with write concerns. * - ``:write`` - Deprecated. Same as ``:write_concern``. The options can be provided as the last argument to the write stream methods: .. code-block:: ruby fs_bucket.open_upload_stream('my-file.txt', write_concern: {w: 2}) do |stream| stream.write_concern # => #2}> # ... end fs_bucket.upload_from_stream('my-file.txt', file, write_concern: {w: 2}) Working with read streams ========================= To download a file from GridFS using a read stream, you can either open a read stream and read from it directly or download the entire file all at once. To open a download stream and read from it: .. code-block:: ruby File.open('/path/to/my-output-file.txt', 'w') do |file| fs_bucket.open_download_stream(file_id) do |stream| file.write(stream.read) end end To download the file all at once and write it to an IO object: .. code-block:: ruby File.open('/path/to/my-output-file.txt', 'w') do |file| fs_bucket.download_from_stream(file_id, file) end You can also download a file specified by a name and (optionally) revision number. Revision numbers are used to distinguish between files sharing the same name, ordered by date of upload. The revision number passed to ``open_download_stream_by_name`` can be positive or negative. .. code-block:: ruby File.open('/path/to/my-output-file.txt', 'w') do |file| fs_bucket.open_download_stream_by_name('my-file.txt', revision: -2) do |stream| file.write(stream.read) end end To download the entire contents of the file specified by name and (optionally) revision number: .. code-block:: ruby File.open('/path/to/my-output-file.txt', 'w') do |file| fs_bucket.download_to_stream_by_name('my-file.txt', file, revision: -2) end Read streams support the following options: .. list-table:: :header-rows: 1 :widths: 40 80 * - Option - Description * - ``:read`` - The read preference to use when downloading files. Some, but not all, of the read methods listed above pass these options to the underlying read streams. Please consult the API documentation for each method to determine whether it supports a particular option. Finding file metadata ===================== You can retrieve documents containing metadata about files in the GridFS files collection. .. code-block:: ruby fs_bucket.find(filename: 'my-file.txt') Deleting files ============== You can delete a file by id. .. code-block:: ruby fs_bucket.delete(file_id) Working with Grid::File objects =============================== This object can be used to wrap a file to be inserted into the database using GridFS and the object that is retrieved. To create a file with raw data: .. code-block:: ruby file = Mongo::Grid::File.new('I am a file', :filename => 'new-file.txt') To create a file from a Ruby ``File`` object: .. code-block:: ruby file = File.open('/path/to/my-file.txt') grid_file = Mongo::Grid::File.new(file.read, :filename => File.basename(file.path)) To change file options such as chunk size, pass options to the constructor: .. code-block:: ruby file = File.open('/path/to/my-file.txt') grid_file = Mongo::Grid::File.new( file.read, :filename => File.basename(file.path), :chunk_size => 1024 ) The following is a full list of the available options that files support. .. list-table:: :header-rows: 1 :widths: 40 80 * - Option - Description * - ``:chunk_size`` - Sets the size of each file chunk in the database. * - ``:content_type`` - Set a content type for the file. * - ``:filename`` (Required) - The file name. * - ``:upload_date`` - The date the file was uploaded (stored). Inserting Files =============== Files can be inserted into the database one at a time. File chunks are inserted by default into the ``fs.chunks`` collection and file metadata is inserted into the ``fs.files`` collection. .. code-block:: ruby client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'music') file = Mongo::Grid::File.new('I am a file', :filename => 'new-file.txt') client.database.fs.insert_one(file) To insert into collections with a name prefix other than `fs`, access the filesystem with a ``:fs_name`` option. .. code-block:: ruby client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'music') file = Mongo::Grid::File.new('I am a file', :filename => 'new-file.txt') client.database.fs(:fs_name => 'grid').insert_one(file) When the driver is inserting the first file into a bucket, it will attempt to create the required indexes on ``files`` and ``chunks`` collections. The required indexes are as follows: .. code-block:: ruby # files collection { :filename => 1, :uploadDate => 1 } # chunks collection { :files_id => 1, :n => 1 }, { :unique => true } .. note:: If the indexes cannot be created, such as due to the current user lacking the permissions to do so, the file insert will be aborted. If the application does not have permissions to create indexes, a database administrator must create the required indexes ahead of time. If the bucket already has files, the driver will not attempt to create indexes, even if they are missing and the current user has permissions to create them. In this case a database administrator should create the needed indexes as soon as possible to ensure data integrity. Files can also be streamed as an alternative to a direct insert. .. code-block:: ruby client.database.fs.open_upload_stream(filename) do |stream| stream.write(file) end Finding Files ============= To retrieve a file from the database, call ``find_one`` with the appropriate filter. .. code-block:: ruby client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'music') client.database.fs.find_one(:filename => 'new-file.txt') # Returns a Mongo::Grid::File Files can also be streamed as an alternative to a direct find. .. code-block:: ruby client.database.fs.open_download_stream(file_id) do |stream| io.write(stream.read) end fs.download_to_stream(file_id, io) Deleting Files ============== To delete a file, pass the file object to ``delete_one``. .. code-block:: ruby client = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'music') fs = client.database.fs file = fs.find_one(:filename => 'new-file.txt') fs.delete_one(file)