docs icon indicating copy to clipboard operation
docs copied to clipboard

Update an object in array

Open thinklinux opened this issue 10 years ago • 2 comments

Let's say I have table posts and every post have an array called comments with objects inside to describe the comment like so comments: [{author: 'Joe', adminComment: true, text: 'Update me'}]

How would you update the text of the comment? I saw that there is an issue for that but the solution is not available yet.

Stack Overflow to the rescue! There is a good explanation for the update query. The problem was that it is with hard-coded index for the element of the array. So here is a full example for updating a single comment that worked for me:

let post_id = 123;
let comment_id = 23434;

let findCommentIndex =
  r.table("posts")
    .get(post_id)("comments")
    .offsetsOf(
      r.row("id").match(comment_id)
    )
    .nth(0)

let update =
  findCommentIndex.do((index) => {
    return r.table('posts')
      .get(post_id)
      .update((post) => {
        return {
          channels: post('comments').changeAt(index,
            post('comments')
              .nth(index)
              .merge({'text': 'updated!'})
          )
        }
      })
  })

This operations should be a lot more easier and I hope someday they will be but right now it would be cool if we have some examples like this one on the docs or cookbook because I'm sure I'm not the only one that lost a lot of time to figure this one out.

thinklinux avatar Oct 30 '15 08:10 thinklinux

There's also the alternative of using a map for finding and modifying the element in a single pass. It shouldn't make a difference for performance, but is sometimes nicer to write:

let update =
  r.table("posts")
   .get(post_id)
   .update({
     comments: r.row("comments").map((comment) => {
         return r.branch(
             comment("id").eq(comment_id),
             {test: 'updated!'},
             {}
         );
       })
   })

One problem specific to the code above is that it fetches the post twice, once for findCommentIndex and once for update. This means that the operation is not atomic, and things might go wrong if there are any concurrent modifications to the post. The map version shown here doesn't have that problem.

danielmewes avatar Nov 02 '15 23:11 danielmewes

@danielmewes Thanks! More elegant and most important - atomic. Love it!

thinklinux avatar Nov 02 '15 23:11 thinklinux