I've run across MartenDb a number of times over the last couple of years, usually when I was looking for platforms to implement Event Sourcing. Unfortunately, the fact that MartenDb requires PostgreSQL has made it a non-starter at the organizations I've been at since it would introduce an entirely new database platform that is similar to the already established MS SQL server or Oracle.
Recently, I was looking into options for both Event Sourcing as well as a document store. When I came across MartenDb this time I realized that I have AWS Aurora available and it supports PostgreSQL API. This triggered a deep dive into MartenDb and I spent some time exploring the details of how MartenDb works and what benefits it brings. What I found was impressive and motivated me to include it in my latest passion project.
Why not MongoDb?
You may be asking, why not just use MongoDb. Well, I've looked at MongoDb a number of times over the years and I'm just not that impressed. It seems to work well for a small POC or demonstration project, but running it in a secure, resilient and performant implementation is not trivial and likely more expensive than MS SQL Server. Using MongoDb for a small non-critical application in a single node community edition configuration might be fine, but for business critical usage non-functional requirements like encryption at rest, support and protections against data loss are very important and should not be ignored.
My MartenDb Journey
What I learned early in my MartenDb journey is that it was founded by Jeremy Miller. Prior to starting MongoDb, Jeremy Miller was the author of StructureMap, the original IoC/DI container for .NET, among other open source projects. According to Jeremy Miller, MartenDb was originally created as a replacement to RavenDb. Since that time MartenDb has been expanded to include Event Sourcing and multi-tenancy capabilities.
The big difference between MartenDb and other document databases is that it leverages PostgreSQL as the data store. PostgreSQL has unique support for JSON documents with JSONB data type columns. The JSONB datatype allows for efficient queries and indexes of JSON documents stored in JSONB columns.
Documents in the Database
Using a relational database to store JSON or XML documents is something that I personally have a mixed history with. I've used this technique over the years for some scenarios and the part that always burned me was queries of the data within the document and making patches to the documents. Queries of data within the documents is often slow and complex to implement. Patches to the documents require complex and slow DML.
My past experience initially made me skeptical of the MartenDb approach of using a relational database, however once I performed some experiments I was won over. The combination of MartenDb functionality and the JSONB capabilities in PostgreSQL effectively mitigate all of the downsides I've run into when using a relational database for storing documents.
Using PostgreSQL provide MartenDb some distinct and unique advantages that are not present in document stores like MongoDb and RavenDb.
The first advantage is that PostgreSQL is battle tested and widely proven. The creators of MartenDb did not need to figure out how to solve the complex problems associated with creating a database platform from scratch. This allowed the creators to focus on higher level problems that make MartenDb unique.
The second advantage is that because PostgreSQL is a relational database you get familiar consistency models and foreign keys between documents for referential integrity. Most document databases leverage eventual consistency for scale out scenarios and foreign keys and joins are extremely inefficient if they are available at all.
In addition, there are some use cases that are much better served with relational tables over document stores. In these scenarios you can combine a micro-ORM like Dapper with MartenDb to keep all of the relational and document data in the same database. This eliminates the need for distributed transactions and reduces the infrastructure footprint required.
- (Learn about JSONB in PostgreSQL)[https://scalegrid.io/blog/using-jsonb-in-postgresql-how-to-effectively-store-index-json-data-in-postgresql/]
Having multi-tenancy and Event Sourcing built into a document database is unique. Both of these patterns are not trivial to implement and having them as part of a single platform is a powerful combination.
For anyone building a SaaS solution, you know that segmenting the data in a secure way and is something that requires a lot of thought. Remembering to include tenant keys in every query or DML statement is burdensome which makes it easy to inadvertently omit. MartenDb makes including the tenant key for all database interactions (easy to abstract away so that you don't need to think about it)[https://martendb.io/documentation/documents/tenancy/basicoperations/]. In addition the default tenant data capabilities solve the age old issue of where to put data that applies across tenants.
- (MartenDb Multi-tenancy Documentation)[https://martendb.io/documentation/documents/tenancy/]
When designing a schema for a NoSQL database, you need to think about how the data will be consumed and not just about how to efficiently store it. Command Query Segregation known as CQRS and Event Sourcing are complementary patterns that solve this problem. CQRS separates the commands associated with business activities from queries that consume data that results from the commands. Event Sourcing persists each command in an event stream and then emits events to project the data in a format that is designed to be queried.
While I don't think it is wise to apply Event Sourcing to all use cases, having it available and easy to leverage for appropriate use cases seems like a powerful option.
- (MartenDb Event Sourcing Documentation)[https://martendb.io/documentation/events/]
My early exploration and subsequent experiences with building a solution that leverage MartenDb have been a largely positive experience. If you need a document store or Event Sourcing for your implementation and you are using .NET, then I highly recommend you consider MartenDb.