3

I'm having a rather large amount of difficulty with trying to remove nested objects from my table, without accidentally deleting all my data in the process (happened three times now, thank god I made copies).

My Object:

{
  "value1": thing,
  "value2": thing,
  "value3": thing,
  "roles": {
    "1": {
      "name": "Dave",
      "id": "1"
    },
    "2": {
      "name": "Jeff",
      "id": "2"
    },
    "3": {
      "name": "Rick",
      "id": "3"
    },
    "4": {
      "name": "Red",
      "id": "4"
    }
  }
}`

I've tried a number of rethink queries, but none have worked thus far. It should be noted that 1, 2, 3, & 4 are variables that can have any amount of numbers, and thus my query must reflect that.

Some attempted queries:

function removeRole(id, roleName) {
        let role = `${roleName}`
        return this.r.table('guilds').get(id).replace(function(s){
            return s.without({roles : {[role] : { "name": role }}})
        })
    }
function removeRole(id, roleName) {
        return this.r.table('guilds').getAll(id).filter(this.r.replace(this.r.row.without(roleName))).run()
    }
function removeRole(id, roleName) {
        return this.r.table('guilds').get(id)('roles')(roleName).delete()
    }

Any assistance is greatly appreciated, and if the question has issues, please let me know. Still rather new to this so feedback is appreciated.

1 Answer 1

1

I'm not sure if I understood your intention, but the following query seems to do what you're trying to accomplish:

r.db('test')
  .table('test')
  .get(id)
  .replace((doc) => {
    // This expression makes sure that we delete the specified keys only
    const roleKeys = doc
      .getField('roles')
      .values()
      // Make sure we have a role name is in the names array
      .filter(role => r.expr(names).contains(role.getField('name')))
      // This is a bit tricky, and I believe I implemented this in a not efficient
      // way probably missing a first-class RethinkDB expression that supports
      // such a case out of box. Since we are going to delete by nested dynamic
      // ids, RethinkDB requires special syntax to denote nested ids:
      //     {roles: {ID_1: true, ID_2: true}}
      // Well, this is just a JavaScript syntax workaround, so we're building
      // such an object dynamically using fold.
      .fold({}, (acc, role) => acc.merge(r.object(role.getField('id'), true)));
    return doc.without({roles: roleKeys});
  })

For example, if names is an array, say ['Jeff', 'Rick'], the nested roleKeys expession will be dynamically evaluated into:

{2: true, 3: true}

that is merged into the roles selector, and the above query will transform the document as follows:

{
  "value1": ...,
  "value2": ...,
  "value3": ...,
  "roles": {
    "1": {"name": "Dave", "id": "1"},
    "4": {"name": "Red", "id": "4"}
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Worked like a charm, thanks a bunch. Saved me another set of stress-filled hours today. If I may, why is this method inefficient? It seemed to work perfectly as intended with little room for error that I can see.
@Laz It's nice to hear that I could save some time for you, thank you too! Actually, I'm not really sure if the roleKeys expression can be re-written in a more simple way with some RethinkDB built-ins that can do exactly what I implemented in my answer. I would say that a chain of values, filter, and fold+merge+object looks somewhat clunky to me. If you find a nicer way getting rid of the chain, please feel free to modify my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.