# Storing Binary Data with MongoDB and C++

In modern applications, storing and retrieving binary files efficiently is a crucial requirement. MongoDB enables this with binary data type in the BSON which is a binary serialization format used to store documents in MongoDB. A BSON binary value is a byte array and has a subtype (like generic binary subtype, UUID, MD5, etc.) that indicates how to interpret the binary data. See BSON Types — MongoDB Manual for more information.

In this tutorial, we will write a console application in C++, using the MongoDB C++ driver to upload and download binary data. 

**Note**: 

- When using this method, remember that the BSON document size limit in MongoDB is 16 MB. If your binary files are larger than this limit, consider using GridFS for more efficient handling of large files. See GridFS example in C++ for reference.
- Developers often weigh the trade-offs and strategies when storing binary data in MongoDB. It's essential to ensure that you have also considered different strategies to optimize your data management approach.

## Prerequisites

1. MongoDB Atlas account with a cluster created.
2. IDE (like Microsoft Visual Studio or Microsoft Visual Studio Code) setup with the MongoDB C and C++ Driver installed. Follow the instructions in Getting Started with MongoDB and C++ to install MongoDB C/C++ drivers and set up the dev environment in Visual Studio. Installation instructions for other platforms are available.
3. Compiler with C++17 support (for using `std::filesystem` operations).
4. Your machine’s IP address whitelisted. Note: You can add *0.0.0.0/0* as the IP address, which should allow access from any machine. This setting is not recommended for production use.

## Building the application

> Source code available **here**.

As part of the different BSON types, the C++ driver provides the b_binary struct that can be used for storing binary data value in a BSON document. See the API reference.

We start with defining the structure of our BSON document. We have defined three keys: `name`, `path`, and `data`. These contain the name of the file being uploaded, its full path from the disk, and the actual file data respectively. See a sample document below:

 (URI), update it to `mongoURIStr`, and set the different path and filenames to the ones on your disk.

```cpp
int main()
{
    try
    {
        auto mongoURIStr = "";
        static const mongocxx::uri mongoURI = mongocxx::uri{ mongoURIStr };
        
        // Create an instance.
        mongocxx::instance inst{};
        
        mongocxx::options::client client_options;
        auto api = mongocxx::options::server_api{ mongocxx::options::server_api::version::k_version_1 };
        client_options.server_api_opts(api);
        mongocxx::client conn{ mongoURI, client_options};
        
        const std::string dbName = "fileStorage";
        const std::string collName = "files";
        
        auto fileStorageDB = conn.database(dbName);
        auto filesCollection = fileStorageDB.collection(collName);
        // Drop previous data.
        filesCollection.drop();

        // Upload all files in the upload folder.
        const std::string uploadFolder = "/Users/bishtr/repos/fileStorage/upload/";
        for (const auto & filePath : std::filesystem::directory_iterator(uploadFolder))
        {
            if(std::filesystem::is_directory(filePath))
                continue;

            if(!upload(filePath.path().string(), filesCollection))
            {
                std::cout << "Upload failed for: " << filePath.path().string() << std::endl;
            }
        }

        // Download files to the download folder.
        const std::string downloadFolder = "/Users/bishtr/repos/fileStorage/download/";
        
        // Search with specific filenames and download it.
        const std::string fileName1 = "image-15.jpg", fileName2 = "Hi Seed Shaker 120bpm On Accents.wav";
        for ( auto fileName : {fileName1, fileName2} )
        {
            if (!download(fileName, downloadFolder, filesCollection))
            {
                std::cout << "Download failed for: " << fileName << std::endl;
            } 
        }
        
        // Download all files in the collection.
        auto cursor = filesCollection.find({});
        for (auto&& doc : cursor) 
        {
            auto fileName = std::string(docFILE_NAME].get_string().value);
            if (!download(fileName, downloadFolder, filesCollection))
            {
                std::cout << "Download failed for: " << fileName << std::endl;
            } 
        }
    }
    catch(const std::exception& e)
    {
        std::cout << "Exception encountered: " << e.what() << std::endl;
    }

    return 0;
}
```

## Application in action

Before executing this application, add some files (like images or audios) under the `uploadFolder` directory. 

![Files to be uploaded from local disk to MongoDB.][2]

Execute the application and you’ll observe output like this, signifying that the files are successfully uploaded and downloaded.

![Application output showing successful uploads and downloads.][3]

You can see the collection in [Atlas or MongoDB Compass reflecting the files uploaded via the application.

, offer a powerful solution for handling file storage in C++ applications. We can't wait to see what you build next! Share your creation with the community and let us know how it turned out!

  [1]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt24f4df95c9cee69a/6504c0fd9bcd1b134c1d0e4b/image1.png
  [2]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt7c530c1eb76f566c/6504c12df4133500cb89250f/image3.png
  [3]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt768d2c8c6308391e/6504c153b863d9672da79f4c/image5.png
  [4]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt8c199ec2272f2c4f/6504c169a8cf8b4b4a3e1787/image2.png
  [5]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt78bb48b832d91de2/6504c17fec9337ab51ec845e/image4.png