Sharding: Anchoring Documents
- RavenDB normally selects which bucket to store a document in
by a hash code
based on the document's ID.
Anchoring a document to a bucket gives the user more control over the selection of a document's bucket. - Users cannot explicitly select a document's bucket by number.
They can, however, add the document's ID a suffix by which the document's bucket will be selected. - Documents whose IDs end with the same suffix, will share
a bucket (and therefore a shard).
If the suffix is another document's ID, the anchored document will be stored in the same bucket as that other document. -
Making documents share a bucket is useful when, for example, the documents are related and are expected to often be loaded in the same transaction.
-
In this page:
Overview
To anchor a document, add its ID a suffix: the $
symbol,
followed by the ID of the anchor document.
<anchored document ID
> + $
+ <anchor document ID
>
To determine which bucket a document will be stored in, RavenDB
normally runs a hash algorithm
over the entire document ID and uses the bucket pointed at by the
resulting hash code.
Anchored documents are an exception to this behavior, as RavenDB
runs the hash algorithm only over the ID part following the $
symbol.
If this part is the ID of an anchor document, the anchored and anchor
documents will have the same hash code and be stored in the same bucket.
In the example below, the document named Users/70$Users/4
is placed
in the same bucket as its anchor, Users/4
.
Anchored Documents
-
Users cannot select a document's bucket explicitly by its number, but only by adding a suffix by which the bucket number is calculated.
-
It is possible to anchor multiple documents to the same document.
E.g., naming three documentsUsers/70$Users/4
,Users/71$Users/4
, andUsers/72$Users/4
will make the database store these documents in the same bucket asUsers/4
. -
It is possible to anchor multiple documents to the same bucket using an arbitrary name that represents no existing document.
E.g.,Users/1$foo
andUsers/2$foo
will share a bucket.
Please do not anchor too many documents to the same bucket, to prevent
the creation of an oversized bucket that cannot be split and resharded,
if needed, to balance the database.
Notes about document names:
-
In a document ID that contains multiple
$
symbols, only the suffix following the last$
will be used to calculate the bucket number. -
An anchored document is accessible only by its full name.
E.g.,Users/4
andUsers/4$Users/5
are two different documents, whereUsers/4$Users/5
is anchored toUsers/5
andUsers/4
is not.
Examples
Example 1
Explicitly store a document with another document's name as a suffix,
to keep both documents in the same bucket.
In this case, keep an invoice in the same bucket as its order.
// The invoice will be stored with the order ID as a suffix
session.Store(invoice, invoice.Id + "$" + order.Id);
session.SaveChanges();
Example 2
Define and use a naming convention for invoices.
Whenever an invoice is stored, the $ symbol and an order ID are automatically added
to the invoice's ID to assure that invoices and orders are kept in the same bucket.
// Store an invoice document in the same bucket as its order document
// Register a naming convention for invoices
// When an invoice is stored, the $ symbol and an order ID are added to the invoice ID
var conventions = new DocumentConventions();
conventions.RegisterAsyncIdConvention<Invoice>(async (dbName, r) =>
{
var id = await conventions.AsyncDocumentIdGenerator(dbName, r);
return $"{id}${r.OrderId}";
});
// Implement the naming convention we define above
using (var store = new DocumentStore()
{
Urls = new[] { "http://127.0.0.1:8080" },
Database = "Products",
Conventions = conventions
}.Initialize())
{
using (var session = store.OpenSession())
{
var order = new Order
{
};
session.Store(order);
var invoice = new Invoice
{
OrderId = order.Id
};
// The invoice will be stored with the order ID as a suffix
session.Store(invoice);
session.SaveChanges();
}
}