RavenDB: Attachments (or Blobs)

Today we’re looking at attachments in RavenDB. Attachments allow you to store binary data along your documents. So attachments are basically BLOBs in RavenDB.

Storing Binary Data in Documents

For simply storing some smaller binary data we can put it directly into a document. We just declare a byte array field and put stuff in it. The data will be stored and loaded with the document. RavenDB will store your binary data base64-encoded in the document.

public class BlogPost
{
	public BlogPost(string title)
	{
		Title = title;
	}

	public string Id { get; set; }
	public string Title { get; set; }
	public byte[] Picture { get; set; }
}


However we need to keep in mind that we always load that binary data together with the document. For larger data that can take its time. Therefore we might want to consider to put the larger data chunks in a separate document, so that we can load that in on demand.

Blob in Document

Blob in Document

Attachments

As alternative we can store binary data in attachments. Attachments are completely decoupled from the regular documents. They don’t participate in transactions and can be updated and changed independently from documents. Like this:

var dbCommands = session.Advanced.DatabaseCommands;
// We can freely choose an id.
// I've decided to use the document id to which the attachement belongs to
var optionalMetaData = new RavenJObject();
optionalMetaData["Format"] = "PNG";
dbCommands.PutAttachment(post.Id, Guid.NewGuid(),
	File.ReadAllBytes(@"C:\Users\Gamlor\Desktop\thumb1.png"), optionalMetaData);

The GUID we pass is the Etag used for caching. As long as this Etag is the same the client can get the attachment from its cache. When we replace an attachment but use the same Etag the client can use the cached value. Otherwise it needs to get the new attachment. However caching is a topic for another time.

We can get the attachment via id:

var dbCommands = session.Advanced.DatabaseCommands;
// Now let's get the picture by its id
var attachement = dbCommands.GetAttachment(post.Id);
var thePicture = attachement.Data;
var format = attachement.Metadata["Format"];

File.WriteAllBytes(@"C:\Users\Gamlor\Desktop\tmp.png", thePicture);

To update an attachment we simple use the PutAttachment command again:

// To update a document just use the put command again
dbCommands.PutAttachment("blogposts/3073", Guid.NewGuid(),
    File.ReadAllBytes(@"C:\Users\Gamlor\Desktop\newerImage.png"),
    new RavenJObject());

And to delete it we can use the delete command.

dbCommands.DeleteAttachment(post.Id, null);

RavenDB Attachments

RavenDB Attachments

Update: Use of Attachements for Storing Blobs

@synhershko on Twitter pointed out that out that the use of attachments is discouraged when blobs can be put somewhere else. He’s certainly right. However in my opinion it is still handy to store blobs in attachments, when RavenDB is already up and running and does the job decent enough.

Conclusion

To store binary data we either can store it directly in document or use RavenDB’s attachments. That’s if for today. Next time we look at cascading operations support in RavenDB.

Tagged on: ,

2 thoughts on “RavenDB: Attachments (or Blobs)

  1. RightSide

    If we dont know the file name or file path ahead of time, how would you do that. Instead of
    File.ReadAllBytes(@”C:\Users\Gamlor\Desktop\thumb1.png”), optionalMetaData);
    If I use a variable parameter like..
    File.ReadAllBytes(@fileName, optionalMetaData); its not working for me.. I am letting the user pick a fileName by using a input=file upload control.

  2. gamlerhart Post author

    Hi

    I’m not really familiar with ASP.NET, so I don’t know how to extract the data from a upload. I guess you can somehow root the data to RavenDB. But I don’t have a ready solution for that. Ask on Stackoverflow.

    Cheers, Roman