Replace string value in array

698 views
Skip to first unread message

Mike Sopinka

unread,
Apr 11, 2011, 9:27:19 AM4/11/11
to ravendb
Hello,

I have a roadblock i've hit that I can't seem to find an answer too.
I have an array of strings, and I want to replace one of the values in
that array for all documents.

I found "set-based updates" in the HTML API, which looks close to what
I want to do. Basically I have my document:

{
"Id": 1,
"Comment":
{
"Notes": [ "old", "wpf", "c#" ]
}
}

And I want to do something like:
UPDATE documents
SET value = "new"
WHERE Notes CONTAINS "old"

So the resulting document would be:

{
"Id": 1,
"Comment":
{
"Notes": [ "new", "wpf", "c#" ]
}
}

And I'd want this done for all documents. Is this possible with the
CLIENT API?

Let me know if I need to clarify anything confusing.

Thanks!

Mike

Ayende Rahien

unread,
Apr 11, 2011, 9:34:39 AM4/11/11
to rav...@googlegroups.com
It will look something like:

store.DatabaseCommands.UpdateByIndex("YourIndex", new IndexQuery
{
Query = "Note:old"
}, new PatchRequest[]
{
new PatchRequest
{
Name = "Comment",
Type = PatchCommandType.Modify,
Nested = new PatchRequest[]
{
new PatchRequest
{
Type = PatchCommandType.Remove,
Value = "old"
},
new PatchRequest
{
Type = PatchCommandType.Add,
Value = "new"
}, 
}
},
}, true);

Mike Sopinka

unread,
Apr 11, 2011, 11:18:32 AM4/11/11
to ravendb
Thank you very much, I'm on my way! The only issue I have is that I'm
getting an exception that says: Unable to cast object of type
'Newtonsoft.Json.Linq.JValue' to type 'Newtonsoft.Json.Linq.JObject'.

Also, it is actually an IList<string>, not an array, but the JSON was
still correct above.

My query is as follows: (oldTagName and newTagName are strings, as is
the list trying to be modified)

session.Advanced.DatabaseCommands.UpdateByIndex("MyIndex",
new IndexQuery
{
Query = "Notes:" + oldTagName
},
new PatchRequest[]
{
new PatchRequest
{
Name = "Comment.Notes",
Type = PatchCommandType.Modify,
AllPositions = true,
Nested = new PatchRequest[]
{
new PatchRequest
{
Type = PatchCommandType.Remove,
Value = oldTagName
},
new PatchRequest
{
Type = PatchCommandType.Add,
Value = newTagName
}
}
}
},
false
);

Any ideas that pop into mind?

Thanks,
Mike

On Apr 11, 9:34 am, Ayende Rahien <aye...@ayende.com> wrote:
> It will look something like:
>
> store.DatabaseCommands.UpdateByIndex("YourIndex", new IndexQuery
> {
> Query = "Note:old"}, new PatchRequest[]
>
> {
> new PatchRequest
> {
> Name = "Comment",
> Type = PatchCommandType.Modify,
> Nested = new PatchRequest[]
> {
> new PatchRequest
> {
> Type = PatchCommandType.Remove,
> Value = "old"},
>
> new PatchRequest
> {
> Type = PatchCommandType.Add,
> Value = "new"
> },
>
>
>
> }
> },
> }, true);
> On Mon, Apr 11, 2011 at 4:27 PM, Mike Sopinka <msopi...@gmail.com> wrote:
> > Hello,
>
> > I have a roadblock i've hit that I can't seem to find an answer too.
> > I have an array of strings, and I want to replace one of the values in
> > that array for all documents.
>
> > I found "set-based updates" in the HTML API, which looks close to what
> > I want to do. Basically I have my document:
>
> > {
> > "Id": 1,
> > "Comment":
> > {
> > "Notes": [ "old", "wpf", "c#" ]
> > }
> > }
>
> > And I want to do something like:
> > UPDATE documents
> > SET value = "new"
> > WHERE Notes CONTAINS "old"
>
> > So the resulting document would be:
>
> > {
> > "Id": 1,
> > "Comment":
> > {
> > "Notes": [ "new", "wpf", "c#" ]
> > }
> > }
>
> > And I'd want this done for all documents. Is this possible with the
> > CLIENT API?
>
> > Let me know if I need to clarify anything confusing.
>
> > Thanks!
>
> > Mike- Hide quoted text -
>
> - Show quoted text -

Ayende Rahien

unread,
Apr 12, 2011, 9:21:47 AM4/12/11
to rav...@googlegroups.com

store.DatabaseCommands.UpdateByIndex("MyIndex",
   new IndexQuery
   {
  Query = "note:" + oldTagName
   },
   new[]
    {
        new PatchRequest
        {
            Name = "Comment",
            Type = PatchCommandType.Modify,
            AllPositions = true,
            Nested = new[]
            {
                new PatchRequest
                {
                    Type = PatchCommandType.Remove,
  Name = "Notes",
                    Value = oldTagName
                },
                new PatchRequest
                {
                    Type = PatchCommandType.Add,
  Name = "Notes",
                    Value = "new"
                }
            }
        }
    },
   false
);

Mike Sopinka

unread,
Apr 13, 2011, 9:34:07 AM4/13/11
to ravendb
Since "Notes" was a list, it had a $type and $values when I looked at
the document in the web interface. So instead of setting the "Name"
to "Notes" in the nested patching, I set it to $values, and this did
the trick. It's working as I'd like!

Thank you so much for your help Ayende!
> > > - Show quoted text -- Hide quoted text -

Jon Wynveen

unread,
Jul 19, 2012, 12:33:08 PM7/19/12
to rav...@googlegroups.com
I'm trying to do something similar using code from Oren above, but it doesn't seem to be working. I have Roles documents that have a Permissions array, and I'm trying to remove a permission from all users.

An example role document:
{
  "Name": "LC Administrator",
  "Permissions": [
    "Read",
    "Write",
    "Delete",
    "ViewPerformanceDiagnostics",
    "PreviewEmailsInBrowser",
    "ManageUsers"
  ],
  "CreatedOn": "0001-01-01T00:00:00.0000000",
  "CreatedBy": null,
  "ModifiedOn": "2012-07-18T18:13:25.4103944Z",
  "ModifiedBy": "users/1",
  "IsDeleted": false
}

I'm trying to remove the "Read" value with this code. It doesn't error or anything, it just doesn't seem to be removing that value at all.

RavenSession.Advanced.DocumentStore.DatabaseCommands
.PutIndex("Roles/All",
   new IndexDefinitionBuilder<Role>
   {
       Map = roles => from role in roles
           select new {role.Name, role.Permissions, role.IsDeleted}
   });

RavenSession.Advanced.DocumentStore.DatabaseCommands
.UpdateByIndex("Roles/All",
       new IndexQuery{Query="IsDeleted:false"},
       new[]
       {
        new PatchRequest
        {
        Name = "Permissions",
        Type = PatchCommandType.Modify,
AllPositions = true,
        Nested =
           new[]
               {
                   new PatchRequest
                      {
                      Type = PatchCommandType.Remove,
                      Value = "Read"
                      }
               }
        }
       }, true);

This is my first attempt at a patch like this, so I'm not sure if I'm doing anything wrong in here or if the syntax has changed since this original post.
Message has been deleted

Oren Eini (Ayende Rahien)

unread,
Jul 19, 2012, 6:35:04 PM7/19/12
to rav...@googlegroups.com
Remove  AllPositions = true,
         
What happens then?

Jon Wynveen

unread,
Jul 20, 2012, 9:47:28 AM7/20/12
to rav...@googlegroups.com
When I remove the AllPositions, it gives me this error:

Cannot modify value from  'Permissions' because position element does not exists or not an integer and allPositions is not set

But today even when I run it with AllPositions still in there, I'm getting this error:

Url: "/bulk_docs/Roles/All?query=IsDeleted%253Afalse&start=0&pageSize=128&aggregation=None&allowStale=True"

System.InvalidCastException: Unable to cast object of type 'Raven.Json.Linq.RavenJValue' to type 'Raven.Json.Linq.RavenJObject'.
  at Raven.Json.Linq.Extensions.Convert[U](RavenJToken token, Boolean cast) in c:\Builds\RavenDB-Stable\Raven.Abstractions\Json\Linq\Extensions.cs:line 131

Oren Eini (Ayende Rahien)

unread,
Jul 21, 2012, 4:01:51 AM7/21/12
to rav...@googlegroups.com
Hm,
The code assumes that if you are going to modify arrays, they are going to be arrays of objects.
You can't do that using the Patch API.

If you can use the new unstable, this becomes:

store.DatabaseCommands.Patch(docId, new AdvancedPatchRequest
{
   Script = "this.Permissions.Remove(perm);",
   Values = {{"perm", "Read"}}
})

On Thu, Jul 19, 2012 at 7:33 PM, Jon Wynveen <jonwy...@gmail.com> wrote:

Jon Wynveen

unread,
Jul 23, 2012, 5:36:49 PM7/23/12
to rav...@googlegroups.com
I updated to the latest unstable just now (2042) and tried that code, but it doesn't compile. It can't convert from AdvancedPatchRequest to PatchRequest.

RavenSession.Advanced.DocumentStore.DatabaseCommands.Patch("roles/1", new PatchRequest[]{
new AdvancedPatchRequest
                                                                      {
                                                                      Script = "this.Permissions.Remove(perm);",
                                                                      Values = {{"perm", "Read"}}
                                                                      }
});

Troy

unread,
Jul 23, 2012, 8:49:47 PM7/23/12
to rav...@googlegroups.com
You may need to get the Nuget package Rx-Linq .. I think this is the one I needed to make it compile..

Troy

unread,
Jul 23, 2012, 8:50:43 PM7/23/12
to rav...@googlegroups.com
Oops, disregard.. I needed that for the new Change API. Sorry.

Matt Warren

unread,
Jul 24, 2012, 3:15:25 AM7/24/12
to rav...@googlegroups.com
There should be an overload of DatabaseCommand.Patch(..) that accepts and AdvancedPatchRequest, do you have that available?

Matt Warren

unread,
Jul 24, 2012, 5:11:24 AM7/24/12
to rav...@googlegroups.com
You need to do this:

RavenSession.Advanced.DocumentStore.DatabaseCommands.Patch("roles/1", new AdvancedPatchRequest
                                                                         {
                                                                         Script = "this.Permissions.Remove(perm);",
                                                                         Values = {{"perm", "Read"}}
                                                                         });

Just pass in an AdvancedPatchRequest directly.

Jon Wynveen

unread,
Jul 24, 2012, 1:38:16 PM7/24/12
to rav...@googlegroups.com
I found that I had updated my version of RavenDB.Database, but not RavenDB.Client. Once I did that it compiled (using the single AdvancedPatchRequest, not an array). But now when I try to run it, I'm getting this error:

Url: "/bulk_docs"

System.ArgumentException: Batching only supports PUT, PATCH and DELETE.
  at Raven.Database.Data.CommandDataFactory.CreateCommand(RavenJObject jsonCommand, TransactionInformation transactionInformation) in c:\Builds\RavenDB-Stable\Raven.Database\Data\CommandDataFactory.cs:line 53
  at Raven.Database.Server.Responders.DocumentBatch.<>c__DisplayClassa.<Batch>b__5(RavenJObject jsonCommand) in c:\Builds\RavenDB-Stable\Raven.Database\Server\Responders\DocumentBatch.cs:line 76
  at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
  at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
  at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
  at Raven.Database.Server.Responders.DocumentBatch.Batch(IHttpContext context) in c:\Builds\RavenDB-Stable\Raven.Database\Server\Responders\DocumentBatch.cs:line 75
  at Raven.Database.Server.Responders.DocumentBatch.Respond(IHttpContext context) in c:\Builds\RavenDB-Stable\Raven.Database\Server\Responders\DocumentBatch.cs:line 38
  at Raven.Database.Server.HttpServer.DispatchRequest(IHttpContext ctx) in c:\Builds\RavenDB-Stable\Raven.Database\Server\HttpServer.cs:line 550
  at Raven.Database.Server.HttpServer.HandleActualRequest(IHttpContext ctx) in c:\Builds\RavenDB-Stable\Raven.Database\Server\HttpServer.cs:line 316

For clarity, here is my code as it stands now:

Matt Warren

unread,
Jul 24, 2012, 5:20:29 PM7/24/12
to rav...@googlegroups.com
It looks like you have an old version of the ravendb server. Have you updated the entire server to a new build?

Kijana Woodard

unread,
Jul 24, 2012, 5:37:21 PM7/24/12
to rav...@googlegroups.com
This happened to me last night. It turns out I got build 616 through NSB and got this error accessing it with a 960 client. 

Now, to figure out why 616 was bundled with NSB 3.2.6.......or how I lost my mind and got into an old nsb folder.
Reply all
Reply to author
Forward
0 new messages