RethinkDB - Updating nested array

后端 未结 6 2323
隐瞒了意图╮
隐瞒了意图╮ 2021-02-13 02:09

I have a survey table that looks like so:

{
  id: Id,
  date: Date,
  clients: [{
    client_id: Id,
    contacts: [{
      contact_id: Id,
      score: Number,
         


        
6条回答
  •  星月不相逢
    2021-02-13 02:19

    ReQL solution

    Creating a query to update a JSON array of objects in-place, is a rather complicated process in ReThinkDB (and most query languages). The best (and only) solution in ReQL that I know about, is to use a combination of update,offsetsOf,do,changeAt, and merge functions. This solution will retain the order of objects in the array, and only modify values on objects which match in the offsetsOf methods.

    The following code (or something similar) can be used to update an array of objects (i.e. clients) which contain an array of objects (i.e. contracts).

    Where '%_databaseName_%', '%_tableName_%', '%_documentUUID_%', %_clientValue_%, and %_contractValue_% must be provided.

    r.db('%_databaseName_%').table('%_tableName_%').get('%_documentUUID_%').update(row =>
    
        row('clients')
          .offsetsOf(clients => client('client_id').eq('%_clientValue_%'))(0)
          .do(clientIndex => ({
    
            clients: row('clients')(clientIndex)
              .offsetsOf(contacts => contact('contact_id').eq('%_contactValue_%')))(0)
              .do(contactIndex => ({
                contacts: row(clientIndex)
                  .changeAt(contractIndex, row(clientIndex)(contractIndex).merge({
                    'score': 0,
                    'feedback': 'xyz'
                  }))
              })
          }))
    )
    

    Why go through the trouble of forming this into ReQL?

      survey 
        .pluck({ clients: 'contacts' }).run()
        .then(results => {
    
          results.clients.forEach((item, outerIndex) => {
            item.contacts.forEach((item, index, array) => {
              if(Number(item.contact_id) === Number(obj.contact_id)) {
                array[index].score = obj.score;
                console.log(outerIndex, index);
              }
            });
          });
    
          return survey.update(results).run()
        })
    

    While the code provided by Jacob (the user who asked the question here on Stack Overflow - shown above) might look simpler to write, the performance is probably not as good as the ReQL solution.

    1) The ReQL solution runs on the query-server (i.e. database side) and therefore the code is optimized during the database write (higher performance). Whereas the code above, does not make full use of the query-server, and makes a read and write request pluck().run() and update().run(), and data is processed on the client-request side (i.e. NodeJs side) after the pluck() query is run (lower performance).

    2) The above code requires the query-server to send back all the data to the client-request side (i.e. NodeJs side) and therefore the response payload (internet bandwidth usage / download size) can be several megabytes. Whereas the ReQL solution is processed on the query-server, and therefore the response payload typically just confirms that the write was completed, in other words only a few bytes are sent back to the client-request side. Which is done in a single request.

    ReQL is too complicated

    However, ReQL (and especially SQL) seem overly complicated when working with JSON, and it seems to me that JSON should be used when working with JSON.

    I've also proposed that the ReThinkDB community adopt an alternative to ReQL that uses JSON instead (https://github.com/rethinkdb/rethinkdb/issues/6736).

    The solution to updating nested JSON arrays should be as simple as...

    r('database.table').update({
      clients: [{
        client_id: 0,
        contacts: [{
          contact_id: 0,
          score: 0,
          feedback: 'xyz',
        }]
      }]
    });
    

提交回复
热议问题