# Seamless Media Storage: Integrating Azure Blob Storage and MongoDB with Spring Boot

From social media to streaming services, many applications require a mixture of different types of data. If you are designing an application that requires storing images or videos, a good idea is to store your media using a service specially designed to handle large objects of unstructured data. 

Your MongoDB database is not the best place to store your media files directly. The maximum BSON document size is 16MB. This helps ensure that a single document cannot use an excessive amount of RAM or, during transmission, an excessive amount of bandwidth. This provides an obstacle as this limit can easily be surpassed by images or videos. 

MongoDB provides GridFS as a solution to this problem. MongoDB GridFS is a specification for storing and retrieving large files that exceed the BSON-document size limit and works by dividing the file into chunks and storing each chunk as a separate document. In a second collection, it stores the metadata for these files, including what chunks each file is composed of. While this may work for some use cases, oftentimes, it is a good idea to use a service dedicated to storing large media files and linking to that in your MongoDB document. Azure Blob (**B**inary **L**arge **Ob**jects) Storage is optimized for storing massive amounts of unstructured data and designed for use cases such as serving images directly to a browser, streaming video and audio, etc. Unstructured data is data that doesn't conform to a specific data model or format, such as binary data (how we store our media files).

In this tutorial, we are going to build a Java API with Spring Boot that allows you to upload your files, along with any metadata you wish to store. When you upload your file, such as an image or video, it will upload to Azure Blob Storage. It will store the metadata, along with a link to where the file is stored, in your MongoDB database. This way, you get all the benefits of MongoDB databases while taking advantage of how Azure Blob Storage deals with these large files.

 or higher
 - Maven or Gradle, but this tutorial will reference Maven
 - A MongoDB cluster deployed and configured; if you need help, check out our MongoDB Atlas tutorial on how to get started
 - An Azure account with an active subscription

## Set up Azure Storage

There are a couple of different ways you can set up your Azure storage, but we will use the Microsoft Azure Portal. Sign in with your Azure account and it will take you to the home page. At the top of the page, search "Storage accounts."

.

Select the subscription and resource group you wish to use, and give your storage account a name. The region, performance, and redundancy settings are depending on your plans with this application, but the lowest tiers have all the features we need.

In networking, select to enable public access from all networks. This might not be desirable for production but for following along with this tutorial, it allows us to bypass configuring rules for network access.

For everything else, we can accept the default settings. Once your storage account is created, we’re going to navigate to the resource. You can do this by clicking “Go to resource,” or return to the home page and it will be listed under your resources.

The next step is to set up a container. A container organizes a set of blobs, similar to a directory in a file system. A storage account can include an unlimited number of containers, and a container can store an unlimited number of blobs. On the left blade, select the containers tab, and click the plus container option. A menu will come up where you name your container (and configure access level if you don't want the default, private). Now, let's launch our container!

In order to connect your application to Azure Storage, create your `Shared Access Signature` (SAS). SAS allows you to have granular control over how your client can access the data. Select “Shared access signature” from the left blade menu and configure it to allow the services and resource types you wish to allow. For this tutorial, select “Object” under the allowed resource types. Object is for blob-level APIs, allowing operations on individual blobs, like uploading, downloading, or deleting an image. The rest of the settings you can leave as the default configuration. If you would like to learn more about what configurations are best suited for your application, check out Microsoft’s documentation. Once you have configured it to your desired settings, click “Generate SAS and connection string.” Your SAS will be generated below this button.

 and click “Connect.” If you need help, check out our guide in the docs.

. With MongoRepository, you don’t need to provide implementation code for many basic CRUD methods for your MongoDB database, such as save, findById, findAll, delete, etc. Spring Data MongoDB automatically generates the necessary implementation based on the method names and conventions.

Now that we have the repository set up, it's time to set up our service layer. This acts as the intermediate between our repository (data access layer) and our controller (REST endpoints) and contains the applications business logic. We'll create another package `com.example.azureblob.service` and add our class `ImageMetadataService.java`.

```java
@Service
public class ImageMetadataService {

    @Autowired
    private ImageMetadataRepository imageMetadataRepository;
    
    @Value("${spring.cloud.azure.storage.blob.container-name}")
    private String containerName;
    
    @Value("${azure.blob-storage.connection-string}")
    private String connectionString;

    private BlobServiceClient blobServiceClient;

    @PostConstruct
    public void init() {
        blobServiceClient = new BlobServiceClientBuilder().connectionString(connectionString).buildClient();
    }

    public ImageMetadata save(ImageMetadata metadata) {
        return imageMetadataRepository.save(metadata);
    }

    public List findAll() {
        return imageMetadataRepository.findAll();
    }

    public Optional findById(String id) {
        return imageMetadataRepository.findById(id);
    }
    
    public String uploadImageWithCaption(MultipartFile imageFile, String caption) throws IOException {
        String blobFileName = imageFile.getOriginalFilename();
        BlobClient blobClient = blobServiceClient.getBlobContainerClient(containerName).getBlobClient(blobFileName);

        blobClient.upload(imageFile.getInputStream(), imageFile.getSize(), true);

        String imageUrl = blobClient.getBlobUrl();
        
        ImageMetadata metadata = new ImageMetadata();
        metadata.setCaption(caption);
        metadata.setImageUrl(imageUrl);
        
        imageMetadataRepository.save(metadata);

        return "Image and metadata uploaded successfully!";
    }
}
```

Here we have a couple of our methods set up for finding our documents in the database and saving our metadata. Our `uploadImageWithCaption` method contains the integration with Azure Blob Storage. Here you can see we create a `BlobServiceClient` to interact with Azure Blob Storage. After it succeeds in uploading the image, it gets the URL of the uploaded blob. It then stores this, along with our other metadata for the image, in our MongoDB database.

Our last step is to set up a controller to establish our endpoints for the application. In a Spring Boot application, controllers handle requests, process data, and produce responses, making it possible to expose APIs and build web applications. Create a package `com.example.azureblob.service` and add the class `ImageMetadataController.java`.

```java
@RestController
@RequestMapping("/image-metadata")
public class ImageMetadataController {

@Autowired
private ImageMetadataService imageMetadataService;

@PostMapping("/upload")
public String uploadImageWithCaption(@RequestParam("image") MultipartFile imageFile, @RequestParam("caption") String caption) throws IOException {
return imageMetadataService.uploadImageWithCaption(imageFile, caption);
}

@GetMapping("/")
public List getAllImageMetadata() {
return imageMetadataService.findAll();
}

@GetMapping("/{id}")
public ImageMetadata getImageMetadataById(@PathVariable String id) {
return imageMetadataService.findById(id).orElse(null);
}
}
```

Here we're able to retrieve all our metadata documents or search by `_id`, and we are able to upload our documents. 

This should be everything you need to upload your files and store the metadata in MongoDB. Let's test it out! You can use your favorite tool for testing APIs but I'll be using a cURL command. 

```console
curl -F "image=mongodb-is-webscale.png" -F "caption=MongoDB is Webscale" http://localhost:8080/blob/upload
```

Now, let's check how that looks in our database and Azure storage. If we look in our collection in MongoDB, we can see our metadata, including the URL to the image. Here we just have a few fields, but depending on your application, you might want to store information like when this document was created, the filetype of the data being stored, or even the size of the file.

, such as How to Use Azure Functions with MongoDB Atlas in Java.

  [1]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltb4993e491194e080/65783b3f2a3de32470d701d9/image3.png
  [2]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blte01b0191c2bca39b/65783b407cf4a90e91f5d32e/image5.png
  [3]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt64cc0729a4a237b9/65783b400d1fdc1b0b574582/image1.png
  [4]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltf9ecb0e59cab32f5/65783b40bd48af73c3f67c16/image6.png
  [5]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/bltfb7a72157e335d34/65783b400f54458167a01f00/image4.png
  [6]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt3117132d54aee8a1/65783b40fd77da8557159020/image7.png
  [7]: https://images.contentstack.io/v3/assets/blt39790b633ee0d5a7/blt0807cbd5641b1011/65783b402813253a07cd197e/image2.png