Skip to content

Commit c99c41d

Browse files
Akash PorwalAkash Porwal
Akash Porwal
authored and
Akash Porwal
committed
[FEATURE] - Added support for mapping nested json keys
1 parent ebdbb43 commit c99c41d

File tree

3 files changed

+157
-81
lines changed

3 files changed

+157
-81
lines changed

README.md

Lines changed: 115 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,34 @@ A Node package for transforming(mapping) one JSON object to another based on a s
1313

1414
#### Input
1515
var input = {
16-
"id" : 101,
17-
"content" : "My first npm package",
18-
"latitude" : 28.7123,
19-
"longitude" : 78.72346,
20-
"user" : {
21-
"id" : 201,
22-
"name" : "Codeslayer",
16+
"id": 101,
17+
"content": "My first npm package",
18+
"latitude": 28.7123,
19+
"longitude": 78.72346,
20+
"user": {
21+
"id": 201,
22+
"name": "Codeslayer",
2323
"interests": [
2424
{
2525
"id": 301,
2626
"tag_id": 401,
2727
"tag": "Food",
2828
"types": {
29-
"id" : 501,
29+
"id": 501,
3030
"name": "Fast foods",
3131
"description": "Unhealthy",
32+
"extras": {
33+
"price": "high",
34+
"health": "low"
35+
},
3236
"contents": [
3337
{
34-
"id" : 601,
35-
"name" : "Pizza"
38+
"id": 601,
39+
"name": "Pizza"
3640
},
3741
{
38-
"id" : 602,
39-
"name" : "Chicken Rice"
42+
"id": 602,
43+
"name": "Chicken Rice"
4044
}
4145
]
4246
},
@@ -48,17 +52,25 @@ A Node package for transforming(mapping) one JSON object to another based on a s
4852
"tag_id": 402,
4953
"tag": "Movie",
5054
"types": {
51-
"id" : 502,
55+
"id": 502,
5256
"name": "Comedy",
5357
"description": "Fun to watch",
58+
"extras": {
59+
"price": "medium",
60+
"entertainment": "decent"
61+
},
5462
"contents": [
5563
{
56-
"id" : 603,
57-
"name" : "Scary Movie"
64+
"id": 603,
65+
"name": "Scary Movie"
66+
},
67+
{
68+
"id": 604,
69+
"name": "Jumanji"
5870
},
5971
{
60-
"id" : 604,
61-
"name" : "Jumanji"
72+
"id": 605,
73+
"name": "Gravity"
6274
}
6375
]
6476
},
@@ -74,39 +86,51 @@ A template specifies how the input json should be transformed to the desired out
7486

7587
**Update**: Starting version **0.1.4**, all keys to be included(and not to be renamed) in output json can be defined in an array named `includeTheseKeys` instead of mapping them one to one(see sample). Prior to **0.1.4**, all keys to be included in output needs to be mapped one to one.
7688

89+
**Update 2**: Version **0.1.5** and above, now support mapping nested keys using **.** as identifier for nesting. Ref example.
90+
7791
**Example:** In the sample below, `id` key from input transforms to `user_id` key in output json. `content` and `latitude` key need not be renamed so they are defined in `includeTheseKeys` array.
7892

7993
For the nested `user` object, the desired key is `userDetails`, so in the output, the data(specified by template `desiredData`) for `user` object comes under the key `userDetails`. The `longitude` key is not specified in template, so it is omitted from the ouput json.
8094

8195
var template = {
82-
"id" : "user_id",
83-
"includeTheseKeys" : ["content", "latitude],
84-
"user" : {
96+
"id": "user_id",
97+
"includeTheseKeys": [
98+
"content",
99+
"latitude"
100+
],
101+
"user": {
85102
"desiredKey": "userDetails",
86103
"desiredData": {
87104
"id": "id",
88105
"name": "first_name",
89106
"interests": {
90107
"desiredKey": "interests",
91-
"desiredData": [{
108+
"desiredData": [
109+
{
92110
"id": "id",
93111
"tag": "tag",
112+
"types.name": "types_name",
113+
"types.extras.health": "extras_health",
114+
"types.contents[2].name": "third_content",
94115
"types": {
95116
"desiredKey": "mappedTypes",
96117
"desiredData": {
97-
"id" : "type_id",
118+
"id": "type_id",
98119
"name": "type_name",
99120
"description": "type_description",
100121
"contents": {
101122
"desiredKey": "mappedContents",
102-
"desiredData": [{
103-
"id" : "id",
104-
"name" : "name"
105-
}]
123+
"desiredData": [
124+
{
125+
"id": "id",
126+
"name": "name"
127+
}
128+
]
106129
}
107130
}
108131
}
109-
}]
132+
}
133+
]
110134
}
111135
}
112136
}
@@ -117,59 +141,73 @@ For the nested `user` object, the desired key is `userDetails`, so in the output
117141
var output = JSONTransform.transform(input, template);
118142
------------------------------------------------------
119143
{
120-
"user_id": 101,
121-
"content": "My first npm package",
122-
"latitude": 28.7123,
123-
"userDetails": {
124-
"id": 201,
125-
"first_name": "Codeslayer",
126-
"interests": [
127-
{
128-
"id": 301,
129-
"tag": "Food",
130-
"mappedTypes": {
131-
"type_id": 501,
132-
"type_name": "Fast foods",
133-
"type_description": "Unhealthy",
134-
"mappedContents": [
135-
{
136-
"id": 601,
137-
"name": "Pizza"
138-
},
139-
{
140-
"id": 602,
141-
"name": "Chicken Rice"
142-
}
143-
]
144-
}
145-
},
146-
{
147-
"id": 302,
148-
"tag": "Movie",
149-
"mappedTypes": {
150-
"type_id": 502,
151-
"type_name": "Comedy",
152-
"type_description": "Fun to watch",
153-
"mappedContents": [
154-
{
155-
"id": 603,
156-
"name": "Scary Movie"
157-
},
158-
{
159-
"id": 604,
160-
"name": "Jumanji"
161-
}
162-
]
144+
"success": true,
145+
"data": {
146+
"user_id": 101,
147+
"content": "My first npm package",
148+
"latitude": 28.7123,
149+
"userDetails": {
150+
"id": 201,
151+
"username": "Codeslayer",
152+
"interests": [
153+
{
154+
"id": 301,
155+
"tag": "Food",
156+
"types_name": "Fast foods",
157+
"extras_health": "low",
158+
"third_content": null,
159+
"mappedTypes": {
160+
"type_id": 501,
161+
"type_name": "Fast foods",
162+
"type_description": "Unhealthy",
163+
"mappedContents": [
164+
{
165+
"id": 601,
166+
"name": "Pizza"
167+
},
168+
{
169+
"id": 602,
170+
"name": "Chicken Rice"
171+
}
172+
]
173+
}
174+
},
175+
{
176+
"id": 302,
177+
"tag": "Movie",
178+
"types_name": "Comedy",
179+
"extras_health": null,
180+
"third_content": "Gravity",
181+
"mappedTypes": {
182+
"type_id": 502,
183+
"type_name": "Comedy",
184+
"type_description": "Fun to watch",
185+
"mappedContents": [
186+
{
187+
"id": 603,
188+
"name": "Scary Movie"
189+
},
190+
{
191+
"id": 604,
192+
"name": "Jumanji"
193+
},
194+
{
195+
"id": 605,
196+
"name": "Gravity"
197+
}
198+
]
199+
}
163200
}
164-
}
165-
]
201+
]
202+
}
166203
}
167204
}
168205

169206
## Release History
170207

171-
* 0.1.0 Initial release
172-
* 0.1.1 Fixed blank values in array
173-
* 0.1.2 Bug fix for array exceeding bounds
174-
* 0.1.3 Handling for undefined keys in JSON
175-
* 0.1.4 Added functionality to define all keys to be included in output json, in an array instead of mapping one to one
208+
* **0.1.0** Initial release
209+
* **0.1.1** Fixed blank values in array
210+
* **0.1.2** Bug fix for array exceeding bounds
211+
* **0.1.3** Handling for undefined keys in JSON
212+
* **0.1.4** Added functionality to define all keys to be included in output json, in an array instead of mapping one to one
213+
* **0.1.5** Added support for mapping nested json keys

index.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,51 @@ var JSONTransform = {
4949
}
5050
}
5151
else if(actualKey == 'includeTheseKeys' && Utils.isArray(template[actualKey])){
52-
console.log("Inside includeTheseKeys with array :: %j",template[actualKey]);
5352
for(var index = 0; index < template[actualKey].length; index++){
5453
var key = template[actualKey][index];
5554
transformedObject[key] = input[key];
5655
}
5756
}
5857
else{
5958
var desiredKeyName = template[actualKey];
60-
transformedObject[desiredKeyName] = input[actualKey];
59+
//check if deep nesting is required(actual key name contains .) and set desiredKey value to deep nested value fetched recursively
60+
var actualKeysArray = actualKey.split('.');
61+
62+
if(actualKeysArray.length > 1){
63+
var lastDeepNestedKeyValue = input[actualKeysArray[0]];
64+
65+
for(var i=1 ; i<actualKeysArray.length; i++){
66+
//check if required deep nested key is an array and fetch and set array value against desiredKey
67+
var indexOfArrayStart = actualKeysArray[i].indexOf('[');
68+
var indexOfArrayEnd = actualKeysArray[i].indexOf(']');
69+
var keyName = actualKeysArray[i];
70+
71+
if(indexOfArrayStart > -1) {
72+
keyName = actualKeysArray[i].substring(0, indexOfArrayStart);
73+
var keyIndex = actualKeysArray[i].substring(indexOfArrayStart+1, indexOfArrayEnd);
74+
75+
if(lastDeepNestedKeyValue == null || !lastDeepNestedKeyValue.hasOwnProperty(keyName)) {
76+
lastDeepNestedKeyValue = null;
77+
}
78+
else{
79+
lastDeepNestedKeyValue = lastDeepNestedKeyValue[keyName][keyIndex];
80+
}
81+
}
82+
else{
83+
if(lastDeepNestedKeyValue == null || !lastDeepNestedKeyValue.hasOwnProperty(keyName)) {
84+
lastDeepNestedKeyValue = null;
85+
}
86+
else {
87+
lastDeepNestedKeyValue = lastDeepNestedKeyValue[actualKeysArray[i]];
88+
}
89+
}
90+
}
91+
92+
transformedObject[desiredKeyName] = lastDeepNestedKeyValue;
93+
}
94+
else {
95+
transformedObject[desiredKeyName] = input[actualKey];
96+
}
6197
}
6298
}
6399

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "json_transform",
3-
"version": "0.1.4",
3+
"version": "0.1.5",
44
"description": "A Node package for transforming(mapping) one JSON object to another based on a specified template",
55
"main": "index.js",
66
"scripts": {
@@ -15,7 +15,9 @@
1515
"mapping",
1616
"mapper",
1717
"transform",
18-
"convert"
18+
"convert",
19+
"nesting",
20+
"nested json"
1921
],
2022
"author": "codeslayer1",
2123
"license": "ISC",

0 commit comments

Comments
 (0)