Search code examples
javascriptjsonnode.jsrethinkdbrethinkdb-javascript

RethinkDB: Javascript - How to deleted nested objects


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.


Solution

  • 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"}
      }
    }