Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
157 views
in Technique[技术] by (71.8m points)

javascript - How to change keys of json object based on different client

i have a requirement where the API response key will be changing depending upon the client for example if I have two client, client 1 and client 2 and my original json data is like below

{
  "destination_addresses": [
    "Washington, DC, USA",
    "Philadelphia, PA, USA",
    "Santa Barbara, CA, USA",
    "Miami, FL, USA",
    "Austin, TX, USA",
    "Napa County, CA, USA"
  ],
  "origin_addresses": [
    "New York, NY, USA"
  ],
  "rows": [{
    "elements": [{
        "distance": {
          "text": "227 mi",
          "value": 365468
        },
        "duration": {
          "text": "3 hours 54 mins",
          "value": 14064
        },
        "status": "OK"
      },
      {
        "distance": {
          "text": "94.6 mi",
          "value": 152193
        },
        "duration": {
          "text": "1 hour 44 mins",
          "value": 6227
        },
        "status": "OK"
      },
      {
        "distance": {
          "text": "2,878 mi",
          "value": 4632197
        },
        "duration": {
          "text": "1 day 18 hours",
          "value": 151772
        },
        "status": "OK"
      },
      {
        "distance": {
          "text": "1,286 mi",
          "value": 2069031
        },
        "duration": {
          "text": "18 hours 43 mins",
          "value": 67405
        },
        "status": "OK"
      },
      {
        "distance": {
          "text": "1,742 mi",
          "value": 2802972
        },
        "duration": {
          "text": "1 day 2 hours",
          "value": 93070
        },
        "status": "OK"
      },
      {
        "distance": {
          "text": "2,871 mi",
          "value": 4620514
        },
        "duration": {
          "text": "1 day 18 hours",
          "value": 152913
        },
        "status": "OK"
      }
    ]
  }],
  "status": "OK"
}

But for client 1 the key should be different like destination_addresses will be dest_address and for client 2 the key will be destaddress and this key change can be done till the child level like the distance key will be dist for client 1 and for client 2 it will be something else so for client 1 For ex the above response for client 1 would be like below

{
  "dest_address": [
    "Washington, DC, USA",
    "Philadelphia, PA, USA",
    "Santa Barbara, CA, USA",
    "Miami, FL, USA",
    "Austin, TX, USA",
    "Napa County, CA, USA"
  ],
  "og_addresses": [
    "New York, NY, USA"
  ],
  "row1": [{
    "elements_client": [{
        "dist": {
          "t": "227 mi",
          "v": 365468
        },
        "duration": {
          "t": "3 hours 54 mins",
          "value": 14064
        },
        "status": "OK"
      },
      {
        "dist": {
          "t": "94.6 mi",
          "value": 152193
        },
        "duration": {
          "t": "1 hour 44 mins",
          "value": 6227
        },
        "status": "OK"
      },
      {
        "dist": {
          "t": "2,878 mi",
          "value": 4632197
        },
        "duration": {
          "t": "1 day 18 hours",
          "value": 151772
        },
        "status": "OK"
      },
      {
        "dist": {
          "t": "1,286 mi",
          "value": 2069031
        },
        "duration": {
          "t": "18 hours 43 mins",
          "value": 67405
        },
        "status": "OK"
      },
      {
        "dist": {
          "t": "1,742 mi",
          "value": 2802972
        },
        "duration": {
          "t": "1 day 2 hours",
          "value": 93070
        },
        "status": "OK"
      },
      {
        "dist": {
          "t": "2,871 mi",
          "value": 4620514
        },
        "duration": {
          "t": "1 day 18 hours",
          "value": 152913
        },
        "status": "OK"
      }
    ]
  }],
  "status": "OK"
}

and it can be different keys for client 2, so how can I achieve this as the object can be nested and the client can be many, I tried a lot of thing like recursion and all but not able to do it and its client specific that's y at last posting my query here, below is the code that I am writing as u can see the parent key I can changes it but the nested i don't know how can I do that

const keys = {
             "destination_addresses":"dest_address",
             "origin_addresses" : "org_address"   
}
const newObj = {};

recursivelyIterateProperties(obj)
function recursivelyIterateProperties(jsonObject,key) {
    if(key){
        if(keys[key]){
            newObj[keys[key]] = jsonObject
        }
    }
    console.log(jsonObject,'<----->>>>>',key)
    if (jsonObject instanceof Array) {
        const d = jsonObject[0];
        if (typeof(d) === 'object'){
            const obj = Object.keys(jsonObject)
            for (var prop in obj) {
                if (!(typeof(jsonObject[obj[prop]]) === 'string')) {
                    recursivelyIterateProperties(jsonObject[obj[prop]],obj[prop]);
                }
            }
        }
        // for (var i = 0; i < jsonObject.length; ++i) {
        //     recursivelyIterateProperties(jsonObject[i],key)
        // }
    }
    else if (typeof(jsonObject) === 'object') {
        const obj = Object.keys(jsonObject)
        for (var prop in obj) {
            if (!(typeof(jsonObject[obj[prop]]) === 'string')) {
                recursivelyIterateProperties(jsonObject[obj[prop]],obj[prop]);
            }else{

            }
        }
    }
}

console.log(newObj);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a potential answer. I'm not thrilled with it, but have no more time to work on it now.

The idea is to use a configuration object like this:

{
  'destination_addresses|#': 'dest_addresses|#',
  'origin_addresses|#': 'og_addresses|#',
  'rows|#|elements|#|distance|text': 'rows|#|elements|#|distance|t',
  'rows|#|elements|#|distance|value': 'rows|#|elements|#|distance|v',
  'rows|#|elements|#|duration|text': 'rows|#|elements|#|duration|t',
  'rows|#|elements|#|duration|value': 'rows|#|elements|#|duration|v',
}

and code which flattens your input object into key-value pairs, where the keys record the object structure, something like this:

[
  ["destination_addresses|0", "Washington, DC, USA"]
  ["destination_addresses|1", "Philadelphia, PA, USA"]
  // ...
  ["origin_addresses|0", "New York, NY, USA"]
  ["rows|0|elements|0|distance|text", "227 mi"]
  ["rows|0|elements|0|distance|value", "365468"]
  ["rows|0|elements|0|duration|text", "3 hours 54 mins"]
  ["rows|0|elements|0|duration|value", "14064"]
  ["rows|0|elements|0|status", "OK"]
  ["rows|0|elements|1|distance|text", "94.6 mi"]
  ["rows|0|elements|1|distance|value", "152193"]
  // ...
  ["rows|0|elements|5|duration|text", "1 day 18 hours"]
  ["rows|0|elements|5|duration|value", "152913"]
  ["rows|0|elements|5|status", "OK"]
  ["status", "OK"]
]

And converting this to

[
  ["dest_addresses|0", "Washington, DC, USA"]
  ["dest_addresses|1", "Philadelphia, PA, USA"]
  // ...
  ["og_addresses|0", "New York, NY, USA"]
  ["rows|0|elements|0|distance|t", "227 mi"]
  ["rows|0|elements|0|distance|v", "365468"]
  ["rows|0|elements|0|duration|t", "3 hours 54 mins"]
  ["rows|0|elements|0|duration|v", "14064"]
  ["rows|0|elements|0|status", "OK"]
  ["rows|0|elements|1|distance|t", "94.6 mi"]
  ["rows|0|elements|1|distance|v", "152193"]
  // ..
  ["rows|0|elements|5|duration|t", "1 day 18 hours"]
  ["rows|0|elements|5|duration|v", "152913"]
  ["rows|0|elements|5|status", "OK"]
  ["status", "OK"]
]

And then finally rehydrating that back into an actual object.

The code in the following snippet does this. It uses some functions with APIs borrowed from Ramda (disclaimer: I'm one of the authors), although the implementations here are different. And it uses a number of generic utility functions, such as getPaths, pathEntries, hydrate, and reconstruct, and then a few helper functions, all of which serve to make the main function, convertStructure, fairly simple.

// Utility functions borrowed from Ramda
const path = (ps = []) => (obj = {}) =>
  ps .reduce ((o, p) => (o || {}) [p], obj)

const assoc = (prop, val, obj) => 
  Number .isInteger (prop) && Array .isArray (obj)
    ? [... obj .slice (0, prop), val, ...obj .slice (prop + 1)]
    : {...obj, [prop]: val}

const assocPath = ([p = undefined, ...ps], val, obj) => 
  p == undefined
    ? obj
    : ps.length == 0
      ? assoc(p, val, obj)
      : assoc(p, assocPath(ps, val, obj[p] || (obj[p] = Number .isInteger (ps[0]) ? [] : {})), obj)


// Generic utility functions
const getPaths = (obj) =>
  Object (obj) === obj
    ? Object .entries (obj) .flatMap (
        ([k, v]) => getPaths (v) .map (p => k + (p ? '|' : '') + p)
      )
    : ['']

const pathEntries = (obj) => 
  getPaths (obj) .map (p => [p, path (p.split('|')) (obj)])

const fixPath = (p) =>
  p .split ('|') .map (n => /^d+$/.test(n) ? Number(n) : n)

const hydrate = (entries) =>
  entries .reduce ((a, [k, v]) => assocPath (fixPath (k), v, a), {})

const reconstruct = (fn) => (obj) => 
  hydrate (fn (pathEntries (obj)))


// Helper functions
const addHash = (config) => (key) =>
  key .split ('|') .map (k => /^d+$/ .test (k) ? '#' : k) .join ('|')

const convertKey = (config) => (key, hashed = addHash (config) (key)) =>
  hashed in config ? config [hashed] : hashed

const reconstituteKey = (template, key, parts = key .split ('|')) => 
  template .split ('|') .map ((k, i) => k == '#' ? parts [i] : k) .join ('|')


// Main function
const convertStructure = (config) => 
  reconstruct (pathEntries => pathEntries .map (
    ([k, v]) => [reconstituteKey (convertKey (config) (k), k), v])
  )


// Sample input
const input = {destination_addresses: ["Washington, DC, USA", "Philadelphia, PA, USA", "Santa Barbara, CA, USA", "Miami, FL, USA", "Austin, TX, USA", "Napa County, CA, USA"], origin_addresses: ["New York, NY, USA"], rows: [{elements: [{distance: {text: "227 mi", value: 365468}, duration: {text: "3 hours 54 mins", value: 14064}, status: "OK"}, {distance: {text: "94.6 mi", value: 152193}, duration: {text: "1 hour 44 mins", value: 6227}, status: "OK"}, {distance: {text: "2,878 mi", value: 4632197}, duration: {text: "1 day 18 hours", value: 151772}, status: "OK"}, {distance: {text: "1,286 mi", value: 2069031}, duration: {text: "18 hours 43 mins", value: 67405}, status: "OK"}, {distance: {text: "1,742 mi", value: 2802972}, duration: {text: "1 day 2 hours", value: 93070}, status: "OK"}, {distance: {text: "2,871 mi", value: 4620514}, duration: {text: "1 day 18 hours", value: 152913}, status: "OK"}]}], status: "OK"}

const config = {
  'destination_addresses|#': 'dest_addresses|#',
  'origin_addresses|#': 'og_addresses|#',
  'rows|#|elements|#|distance|text': 'rows|#|elements|#|distance|t',
  'rows|#|elements|#|distance|value': 'rows|#|elements|#|distance|v',
  'rows|#|elements|#|duration|text': 'rows|#|elements|#|duration|t',
  'rows|#|elements|#|duration|value': 'rows|#|elements|#|duration|v',
}

// Demo
console .log (convertStructure (config) (input))
.as-console-wrapper {max-height: 100% !important; top: 0}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...