Question

Patching RavenDb documents using a Dictionary<string, object>

I'm trying to patch a single/multiple documents (identified by their id) with that I receive in a Dictionary<string, object>. The key of the dictionary is the path to the document property to update, and it may even be a subpath.

So if my document looks like this:

public class MyDoc
{
    public string StringProp {get; set;}
    public bool? BoolProp {get; set;}
    public int? IntProp {get; set;}
    public SubDocument SubProp {get; set;}
}

public class SubDocument
{
    public string StringProp {get; set;}
}

So an example Dictionary may be:

new Dictionary<string, object> 
{ 
    {"StringProp", "hello" },
    {"BoolProp", true },
    {"SubProp.StringProp", "subprop value" },
}

I know how to fetch the document(s), apply the dictionary to it and save the document(s), but I'm looking for a way that doesn't require the extraction of the documents I want to modify.

I'm guessing it would go something along these lines:

 var operation = store
    .Operations
    .Send(new PatchByQueryOperation(new IndexQuery
    {
        QueryParameters = new Parameters
        {
            {"ids", new[] {"orders/1-A", "companies/1-A"}}
        },
         Query = @"from @all_docs as d where id() in ($ids)
          update
          {
              d.StringProp = 'hello';
              d.BoolProp = true;
              d.SubProp.StringProp = 'subprop value';
          }"
}));

And what if SubProp doesn't exist on a document or if I'd like to assign the entire SubProp rather than just fill a property on a subdocument?

 4  50  4
1 Jan 1970

Solution

 2

Regarding your second Question about:
"assigning the entire SubProp rather than just filling a property on a subdocument"

The following will work:

var subObject = new SubDocument() {StringProp = "new sub text"};

var operation = store.Operations.Send(new PatchByQueryOperation(new IndexQuery
{
    QueryParameters = new Parameters
    {
        { "ids", new[] {"myDocs/1", "companies/1-A"} },
        { "subObject", subObject }
    },
    Query = @"from @all_docs as d where id() in ($ids)
                  update
                  {
                      d.StringProp = 'hello';
                      d.BoolProp = false;
                      d.SubProp = ($subObject);
                  }"
}));

Regarding your first Question about:
"what if SubProp doesn't exist on a document"

1. Patching with d.SubProp = 'value1' when SubProp doesn't exist, will succeed and property SubProp will be created with value1.

2. Patching with d.SubProp.StringProp = 'value2' will only succeed if property SubProp is an object type (not a string).


If you need to patch only a single document, then you don't have to use set-based patching.
You can use single-document patching.

Single-document patching is explained by these articles:
(Note: the Node.js article is currently more organized and detailed, the C# article is TBD,
however logic behind is the same)

https://ravendb.net/docs/article-page/latest/nodejs/client-api/operations/patching/single-document https://ravendb.net/docs/article-page/latest/csharp/client-api/operations/patching/single-document

2024-07-09
Danielle