Updating denormalized data

See: Set-based operations

Like most NoSQL solutions, RavenDB best practices favor denormalization over composition / joins for complex documents. A typical example would be storing the Artist name and id along with the Track document:

{
          "Name" : "Fame",
          "Artist": { "Id": "artists/294", "Name": "Irene Cara" }
    }

That decision make reading the data very fast and easy, but it present a challenge when we need to update the Artist name. In general, it isn't recommended to denormalize data that frequently changes, but even rarely changing properties will change occasionally.

In order to solve this exact problem RavenDB offers Set Based Operations. Here is how we can use them from the client API:

documentStore.DatabaseCommands.UpdateByIndex(
	"Tracks/ByArtistId",
	new IndexQuery
		{
			Query = "Artist:artists/294"
		},
	new[]
		 {
			 new PatchRequest
				 {
					 Type = PatchCommandType.Modify, 
					 Name = "Artist", 
					 Nested = new[]
						          {
							          new PatchRequest
								          {
									          Type = PatchCommandType.Set, 
											  Name = "Name", 
											  Value = RavenJToken.FromObject("Fame Soundtrack")
								          }
						          }
				 }
		 },
	allowStale: false);

This will update the Artist.Name property on all the documents where the Tracks/ByArtistId index matched to the id artists/294.

Updating denormalized references using ScriptedPatchRequest

Another approach for denormalized reference updates is to use the ScriptedPatchRequest:

documentStore.DatabaseCommands.UpdateByIndex(
	"Tracks/ByArtistId",
	new IndexQuery {
		Query = "Artist:artists/294"
	},
	new ScriptedPatchRequest() {
		Script = @"
			var artist = LoadDocument(this.Artist.Id);
			this.Artist.Name = artist.Name;
		"
	}, allowStale: false);

As you can see, ScriptedPatchRequest allows us to load a separate document and update our current document based on it's values.