Query to update nested array item without knowing the index

116 views Asked by At

I have a table that contains complex nested documents. The structure of each document is similar to the following example:

{
  "description": "Sample Document",
  "events": [
    {
      "liquids": { ... },
      "protocol": {
        "id": "5b190c4d-6590-49a3-b9a7-69f036f45e55"
      },
      "schedule": { ... }
    },
    {
      "liquids": { ... },
      "protocol": {
        "id": "a4353a88-6021-418f-a18c-0526550edb57",
        "overrides": [
          {
            index: 9,
            values:  {
              foo: "bar"
            }
          {
            index: 7,
            parentIndex: 10,
            values: {
              foo: 8,
              bar: 9
            }
          }
        ]
      },
      schedule: { ... }
    }
  ],
  "id": "7c424fc3-1a58-4a4e-b1b6-8d25412a85da",
  "name": "Sample Doc",
  "project_id": "__ROOT__"
}

I want to update one of the items in the protocol.overrides property of the second item in the events array. I know ahead of time that I need to access myTable.get($id).events(1)('protocol')('overrides') but I have no way of knowing ahead of time which item in the nested array that I need to replace.

In this specific example, lets say that I need to replace the item with index: 7, and parentIndex: 10 (the second item) and lets say that I want to change its values property to {foo: "baz", bar: "curley"}.

I don't see any methods in the reQL API that let me do this. changeAt can be used if I know the array index, but I don't see an indexOf function or anything similar that lets me find the index by matching a predicate.

1

There are 1 answers

0
Kludge On BEST ANSWER

Assuming I understand what exactly you're asking for, including what data is known and what should be queried by it (if not, tweak it), this is how I'd do it:

myTable.get($id) 
  .update(function(row) {
    return {
      events: row('events').map(function(event) {
        return r.branch(
          event('protocol')('overrides').default([]).filter({index: 7}),
          event.merge({
            protocol: {
              overrides: event('protocol')('overrides').default([])
              .map(function(override) {
                return r.branch(
                  override('index').eq(7),
                  override.merge({
                    values: {
                      foo: "baz",
                      bar: "curley"
                    }
                  }),
                  override
                )
              })
            }
          }),
          event
        )
      })
    }
  })

I'm using:

  • .update() method directly on row/s and not on nested data
  • r.branch() for conditions

Not sure this is the best practice, but it seems like it gets the job done.