Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 5,969 | Comments: 44,489

filter by tags archive

Awesome RavenDB Feature of the dayEval Patching, Part II–Denormalized References


I mentioned yesterday that I am keeping the best for today. What I am going to show you is how you can use Eval Patching for keeping track of denormalized references.

In this case, we have Users & Posts. Each Post contains a UserName property as well as the user id. When the user changes his name, we need to update all of the relevant posts.

Here is how you can do this:

store.DatabaseCommands.UpdateByIndex("Posts/ByUser",
    new IndexQuery{Query = "UserId:" + userId},
    new AdvancedPatchRequest
        {
            Script = @"
var user = LoadDocument(this.UserId);
this.UserName = user.Name;
"
        });

And this is a really simple scenario, the options that this opens, the ability to load a separate document and modify the current document based on its value is really powerful.

More posts in "Awesome RavenDB Feature of the day" series:

  1. (26 Jul 2012) Eval Patching, Part II–Denormalized References
  2. (24 Jul 2012) Evil Patching

Comments

Apostol

Wow, so this means that if I have to make this kind of changes - reflect a change from one entity to another - I'm going to make a database command with this kind of script and send it to the server, and the server is going to make the update to all the entities without me needing to load them on client and send them back?

If that's right it's awesome - it's going to make RavenDb much more efficient.

Another question - is there a way to specifying that we want to 'wait for non-stale results' before executing the Script/DatabaseCommand?

Ayende Rahien

Apostol, Yes, that is the idea. And no, there is no way to currently do that.

tobi

It would be a nice idea to have a trigger-like system for such cases. "No matter who changes the name, I want all denormalized data to be updates as well using the following command".

That could be configured at the client, too, if I'm not mistaken. The database does not need to be the driver for triggers.

Khalid Abuhakmeh

What does the document look like when you do an AdvancedPatchRequest, and are AdvancedPatchRequests replicated and part of backup?

Ayende Rahien

Tobi, If you want it done on the client, that is easy, we have listener support for that.

Ayende Rahien

Khalid, APR are commands to the database that modify the state. Their results are written to the db and then treated normally.

Paul Stovell

What happens if the index is stale at the time of the update?

E.g., users/wilma just saved a new post, then changed her name, and the Posts/ByUser index hasn't been updated yet.

Eric J. Smith

Why not use Mono's C# compiler services so that you could write these actions in C# instead of JavaScript?

Matt Warren

@Paul, pass in AllowStale = true as the 4th argument to UpdateByIndex(..) and it'll handle this. Basically the patching won't go ahead if the index is stale at the time.

Matt Warren

@Paul,

Sorry that should've been AllowStale = false and it's actually the default, so it's already handled for you!!

Ayende Rahien

Paul, An exception is thrown, no update takes place.

Ayende Rahien

Eric, Put simply, because it is much easier to limit what you are doing in IronJS than in C#. We already do dynamic compilation, and it is much easier to go this route than that.

Eric J. Smith

I can understand that. It just sucks that the IronJS project seems to have died out.

Rafal

This function looks powerful but ugly and hackishly at the some time - like something unfinished, part of much bigger functionality (a full-blown server side data processing language).

aaron

Perhaps it would be nice to have a small util included which allows you to execute a .cs script from the command line against a raven instance, something like DynamicScriptExecutor.exe Jul27Patch.cs --instance:http://localhost:8090/. which feeds back a success response or any exception info.

Daniel Lang

We can't have any transactional guarantees, right? So is there a way to detect a failure during the updates?

Ayende Rahien

Daniel, This is transactional, like all other things in RavenDB.

njy
njy

@Oren: a suggestion, maybe a stupid one: it would be possible to specify a field as a "computed one"? It would be cool to define a field as computed, specifying the computing algorithm (in JS, of course) and when RavenDB parses that, it will understand which other fields are involved, and keep track of the things automatically.

Think about it: it would be conceptually just like indexes. You don't update indexes values by hand, but instead you specify a map/reduce "logic" and the index values will be updated for you by RavenDB.

The same concept should be used for computed values (typically denormalized values): the dev defines only one time the logic, and RavenDB would do the rest, in the background, when it feels like it should do it. And just like indexes can be stale, computed values could be, too.

There could be 2 ways of doing it, i think, and they would have different consequences:

1) per-field-compute-fiunction: the dev could define the body of a JS function, the return value of which would set the specified field value, like for example "return this.Comments.length" to define the logic for the "CommensCount" field. This function should be run only when one of the fields in the specified formula is updated;

2) per-entity: (like a server-side js entity-update trigger)it could do more stuff, like "this.CommentsCount = this.Comments.length; this.Foo = "Bar" + this.Baz;" or something like that;

What do you think?

Ayende Rahien

Njy, We already have a feature like that, it is called Indexed Properties http://issues.hibernatingrhinos.com/issue/RavenDB-245

borcam

We simplify things a little for this article: The stack keeps track of what is executing in our application. As we enter and exit methods items are added to or removed from the top.

Comment preview

Comments have been closed on this topic.

FUTURE POSTS

  1. Production postmortem: The evil licensing code - 4 hours from now

There are posts all the way to Jul 29, 2015

RECENT SERIES

  1. Production postmortem (5):
    23 Jul 2015 - The case of the native memory leak
  2. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
  3. API Design (7):
    20 Jul 2015 - We’ll let the users sort it out
  4. What is new in RavenDB 3.5 (3):
    15 Jul 2015 - Exploring data in the dark
  5. The RavenDB Comic Strip (3):
    28 May 2015 - Part III – High availability & sleeping soundly
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats