Related
I have 2 or more objects in Main Object.
How can I find one object againt this key value.
{
"0": {
"component": "AWAY",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
},
},
"1": {
"component": "PHONE_BOTH",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
}
},
"2": {
"component": "MEETING_ROOM",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": true,
"image": ""
}
}
}
I just want to get one object where inRoom = true
It is not recommended to index an object with numeric keys. Use an array instead then you can use filter directly on the array
const arr = [{
"component": "AWAY",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
},
},
{
"component": "PHONE_BOTH",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
}
},
{
"component": "MEETING_ROOM",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": true,
"image": ""
}
}
]
console.log(arr.filter(({currentUser}) => currentUser.inRoom === true))
You should convert your dictionary to an array and then find the object by a specific criteria using the find() array method. See implementation:
// usersDict is the given Main Object
// convert usersDict to array of user objects
let usersArray = Object.values(usersDict);
// find user which has inRoom flag true
let userInRoom = usersArray.find(o => !!o.currentUser.inRoom);
var bb = {
"0": {
"component": "AWAY",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
},
},
"1": {
"component": "PHONE_BOTH",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": false,
"image": ""
}
},
"2": {
"component": "MEETING_ROOM",
"currentUser": {
"id": 1,
"userName": "abc",
"inRoom": true,
"image": ""
}
}
}
var kk = []
for (const man in bb) {
if(bb[man].currentUser.inRoom){
kk.push({man: bb[man]})
}
}
console.log(kk.length ? kk[0] : {})
First, you should convert your object to an array then use the filter method in the array:
// obj = your data
Object.values(obj).filter(obj => obj.currentUser.inRoom)
I have 2 responses like below
let response1 = [
{
"rnum": 583,
"status": false,
"id": 24,
"action": "set",
"name": "2726-23",
"fname": [
"xy-01"
],
},
{
"rnum": 593,
"status": false,
"id": 12,
"action": "set",
"name": "2727-5",
"fname": [
"yz-01"
],
}
]
let response2 = [
{
"hName": "yz-01",
"cname": "",
"dlist": "test"
},
{
"hName": "xy-01",
"cname": "",
"dlist": "test"
}
]
here in response1 fname is same as response2 hname so based on this we need to do a mapping
if (response1 fname == response2 hname) then append the particular response2 data to dev([]) in response1
and the final response should be as below. how can we combine 2 responses based on the condition
let finalReposne = [
{
"rnum": 583,
"status": false,
"id": 24,
"action": "set",
"name": "2726-23",
"fname": [
"xy-01"
],
"dev": [
{
"hName": "xy-01",
"cname": "",
"dlist": "test"
}
]
},
{
"rnum": 593,
"status": false,
"id": 12,
"action": "set",
"name": "2727-5",
"fname": [
"yz-01"
],
"dev": [
{
"hName": "yz-01",
"cname": "",
"dlist": "test"
}
]
}
]
Here is an updated solution in response to your comment looking to accommodate multiple fnames.
It first groups the elements in response2 by hName using a .reduce() call.
It then proceeds with a .map() call on response1 in which a second .reduce() call is used to iterate the fname array of the iterated object and retrieve the relevant hName groups. These are combined into a single array using .concat() and added to the object as a dev property.
const
response1 = [{ "rnum": 583, "status": false, "id": 24, "action": "set", "name": "2726-23", "fname": ["xy-01", "zx-02"], }, { "rnum": 593, "status": false, "id": 12, "action": "set", "name": "2727-5", "fname": ["yz-01"], }],
response2 = [{ "hName": "yz-01", "cname": "", "dlist": "test" }, { "hName": "xy-01", "cname": "", "dlist": "test" }, { "hName": "zx-02", "cname": "", "dlist": "test" }],
// group response2 by hName
hnames = response2.reduce((acc, obj) => {
acc[obj.hName] = acc[obj.hName] || [];
acc[obj.hName].push({ name: obj.hName, data: { ...obj } });
return acc;
}, {}),
// map response1 and retrieve/concat hnames into dev
result = response1.map(o => {
const dev = o.fname.reduce((acc, fname) => (acc.concat(hnames[fname] || [])), []);
return { ...o, dev };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Original Answer
Here is a solution using .map() to iterate response1 and return a new array, and a nested .find() call to look for a match in response2. If a match is found we return a copy of the object using destructuring with the match assigned to a new dev property, else just return a copy of the iterated object.
const
response1 = [{ "rnum": 583, "status": false, "id": 24, "action": "set", "name": "2726-23", "fname": ["xy-01"], }, { "rnum": 593, "status": false, "id": 12, "action": "set", "name": "2727-5", "fname": ["yz-01"], }],
response2 = [{ "hName": "yz-01", "cname": "", "dlist": "test" }, { "hName": "xy-01", "cname": "", "dlist": "test" }],
result = response1.map(o => {
const dev = response2.find(({ hName }) => o.fname.includes(hName));
return dev !== undefined ? { ...o, dev: [{ ...dev }] } : { ...o };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Do something like this:
let response1 = [
{
"rnum": 583,
"status": false,
"id": 24,
"action": "set",
"name": "2726-23",
"fname": [
"xy-01"
],
},
{
"rnum": 593,
"status": false,
"id": 12,
"action": "set",
"name": "2727-5",
"fname": [
"yz-01"
],
}
]
let response2 = [
{
"hName": "yz-01",
"cname": "",
"dlist": "test"
},
{
"hName": "xy-01",
"cname": "",
"dlist": "test"
}
]
for (i in response1) {
for (x in response2) {
if (response1[i].fname.includes(response2[x].hName)) {
response1[i].dev = response2[x]
}
}
}
console.log(response1)
This is saying for every entry in response1, check every entry in response2 for a matching hName in the fname.
Check for the decimal id and group them accordingly.
Below are the sample and recommended JSON's
Sample JSON
{
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
Would like to iterate and Re-structure the above JSON into below recommended format.
Logic: Should check the id(with and without decimals) and group them based on the number.
For Example:
1, 1.1, 1.2.3, 1.4.5 => data1: [{id: 1},{id: 1.1}....]
2, 2.3, 2.3.4 => data2: [{id: 2},{id: 2.3}....]
3, 3.1 => data3: [{id: 3},{id: 3.1}]
Recommended JSON
{
"results": [
{
"data1": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
}
]
},
{
"data2": [
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
}
]
},
{
"data3": [
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
}
]
},
{
"data4": [
{
"name": "Download",
"id": "4.2"
}
]
}
]
}
I have tried the below solution but it doesn't group the object
var formatedJSON = [];
results.map(function(d,i) {
formatedJSON.push({
[data+i]: d
})
});
Thanks in advance.
You can use reduce like this. The idea is to create a key-value pair for each data1, data2 etc so that values in this object are the values you need in the final array. Then use Object.values to get those as an array.
const sampleJson = {"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]}
const grouped = sampleJson.results.reduce((a, v) => {
const key = `data${parseInt(v.id)}`;
(a[key] = a[key] || {[key]: []})[key].push(v);
return a;
},{});
console.log({results: Object.values(grouped)})
One liner / Code-golf:
let s={"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]},k;
console.log({results:Object.values(s.results.reduce((a,v)=>(k=`data${parseInt(v.id)}`,(a[k] = a[k]||{[k]:[]})[k].push(v),a),{}))})
Here you go:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
let newSet = new Set();
data.results.forEach(e => {
let key = e.id.substring(0, e.id.indexOf('.'));
console.log(key);
if (newSet.has(key) == false) {
newSet.add(key);
newSet[key] = [];
}
newSet[key].push(e.id);
});
console.log(newSet);
Here's how you'd do it:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
var newData = {
"results": {}
};
data.results.forEach(item => {
var num = item.id.slice(0, 1);
if (newData.results["data" + num]) {
newData.results["data" + num].push(item);
} else {
newData.results["data" + num] = [item];
}
})
data = newData;
console.log(data);
What this does is it iterates through each item in results, gets the number at the front of this item's id, and checks if an array of the name data-{num} exists. If the array exists, it's pushed. If it doesn't exist, it's created with the item.
let input = getInput();
let output = input.reduce((acc, curr)=>{
let {id} = curr;
let majorVersion = 'name' + id.split('.')[0];
if(!acc[majorVersion]) acc[majorVersion]= [];
acc[majorVersion].push(curr);
return acc;
},{})
console.log(output)
function getInput(){
return [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
One solution with RegEx for finer control as it would differentiate easily between 1 and 11.
Also this will make sure that even if the same version comes in end(say 1.9 in end) it will put it back in data1.
let newArr2 = ({ results }) =>
results.reduce((acc, item) => {
let key = "data" + /^(\d+)\.?.*/.exec(item.id)[1];
let found = acc.find(i => key in i);
found ? found[key].push(item) : acc.push({ [key]: [item] });
return acc;
}, []);
So I'm having an issue - I'm getting some data from our internal API at work, but it's not in the correct format I need to do what I have to do, so I have to make some transformations.
For this, I decided to use Lodash, however I'm stuck now.
Basically, I'm working with orders, but some of the products are addons to a parent product. I've managed so far to separate these two types of products, but I don't know how I should go about adding an "addons" array as a child to the parent product with matching ID.
Here's a basic stripped example of the output I'd like:
{
"order": {
"orderLines: [
{
"orderId": "foo",
"addons" [
{
...
}
]
},
{
...
}
]
}
}
And here's my current code:
// TODO:
// Match addons to products based on "connectedTo" => "id", then add matching addons as a new array on parent object
// Base data
const data = {
"order": {
"shopOrderId": "19LQ89H",
"createDate": "2017-10-24T13:09:22.325Z",
"orderLines": [
{
"orderId": "19LQ89H",
"product": {
"productName": "Paintball",
},
"id": "59ef3b8036e16f1c84787c1f",
"stringId": "59ef3b8036e16f1c84787c1f"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Ølsmagning",
},
"id": "59ef3b8036e16f1c84787c20",
"stringId": "59ef3b8036e16f1c84787c20"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "CD-indspilning",
},
"id": "59ef3b8136e16f1c84787c21",
"stringId": "59ef3b8136e16f1c84787c21"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Julefrokost",
},
"id": "59ef3b8236e16f1c84787c22",
"stringId": "59ef3b8236e16f1c84787c22"
},
{
"orderId": "19LQ89H",
"product": {
"productName": "Hummer Limousine",
},
"id": "59ef3b8236e16f1c84787c23",
"stringId": "59ef3b8236e16f1c84787c23"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Ekstra kørsel 400",
},
"id": "59ef3b8236e16f1c84787c24",
"stringId": "59ef3b8236e16f1c84787c24"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Drikkevarer",
},
"id": "59ef3b8236e16f1c84787c25",
"stringId": "59ef3b8236e16f1c84787c25"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c23",
"product": {
"productName": "Drikkevarer",
},
"id": "59ef3b8236e16f1c84787c26",
"stringId": "59ef3b8236e16f1c84787c26"
},
{
"orderId": "19LQ89H",
"connectedTo": "59ef3b8236e16f1c84787c22",
"product": {
"productName": "Snaps ad libitum",
},
"id": "59ef3b8236e16f1c84787c27",
"stringId": "59ef3b8236e16f1c84787c27"
}
],
"travelTimes": [
{
"id": "59ef3b8036e16f1c84787c1f-59ef3b8036e16f1c84787c20",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c1f",
"partyPlanToEventId": "59ef3b8036e16f1c84787c20",
"start": "2017-11-15T17:02:59",
"end": "2017-11-15T17:30:00",
"travelTimeString": "27 min.",
"travelTimeMinutes": 28,
"exceedsAvailableTime": false
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8136e16f1c84787c21",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8136e16f1c84787c21",
"start": "2017-11-15T19:52:12",
"end": "2017-11-15T20:00:00",
"travelTimeString": "8 min.",
"travelTimeMinutes": 8,
"exceedsAvailableTime": false
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8236e16f1c84787c22",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8236e16f1c84787c22",
"start": "2017-11-15T12:30:00",
"end": "2017-11-15T13:00:00",
"travelTimeString": "8 min.",
"travelTimeMinutes": 8,
"exceedsAvailableTime": true
},
{
"id": "59ef3b8036e16f1c84787c20-59ef3b8236e16f1c84787c23",
"partyPlanFromEventId": "59ef3b8036e16f1c84787c20",
"partyPlanToEventId": "59ef3b8236e16f1c84787c23",
"start": "2017-11-15T08:30:00",
"end": "2017-11-15T09:00:00",
"travelTimeString": "3 min.",
"travelTimeMinutes": 4,
"exceedsAvailableTime": true
}
],
"id": "59ef3b8236e16f1c84787c28",
"stringId": "59ef3b8236e16f1c84787c28"
}
}
// Transform data
const travelTimes = data.order.travelTimes.map(item => _.omit(item, ['id']) )
const orderLines = _.merge(data.order.orderLines, travelTimes)
const order = _.omit(data.order, ['orderLines', 'travelTimes'])
const orders = _.assign(order, { orderLines })
const addonGroups = _.groupBy(order.orderLines, 'connectedTo')
const addons = _.omit(addonGroups, 'undefined')
const products = _.pick(addonGroups, 'undefined')
const productGroups = _.groupBy(products.undefined, 'stringId')
console.log(productGroups) // All parent products
console.log(addons) // All addon products
const arr1 = _.values(_.flatMap(productGroups))
const arr2 = _.values(_.flatMap(addons))
Code on Codepen.io
Any help is greatly appreciated!
Let me know if I need to explain in further detail.
Not sure if I understood correctly what the expected result is, but I gave it a try anyway.
const orderLines = _(data.order.orderLines)
.map(item => {
if (!item.connectedTo) return _.assignIn(item, { addons: [] });
const match = _.find(data.order.orderLines, { id: item.connectedTo });
match.addons = match.addons || [];
match.addons.push(item);
return null;
})
.compact()
.value();
Check the output here: https://codepen.io/andreiho/pen/YEzQRd?editors=0012
I have array of objects:
var results= [
{
"_type": "MyType",
"_id": "57623535a44b8f1417740a13",
"_source": {
"info": {
"year": 2010,
"number": "string",
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}
}
];
I need to select specific fields from array. In result, I want to get the following:
[
{
"_id": "57623535a44b8f1417740a13",
"info": {
"year": 2010,
"number": "string"
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}
]
As you can see, I want to select _id field and content of _source object. How can I do this with lodash?
I've found .map function, but it doesn't take array of keys:
var res = _.map(results, "_source");
You could do:
var mapped = _.map(results, _.partialRight(_.pick, ['_id', 'info', 'type', 'date', 'createdBy']));
A little explanation:
_.map(): Expects a function which takes each item from the collection so that you can map it to something else.
_.partialRight(): Takes a function which will be called later on with the its arguments appended to the end
_.pick(): Gets the path specified from the object.
In plain Javascript you could iterate with Array#map and assemble a new object for each object without mutilation the original object.
var results = [{ "_type": "MyType", "_id": "57623535a44b8f1417740a13", "_source": { "info": { "year": 2010, "number": "string", }, "type": "stolen", "date": "2016-06-16T00:00:00", "createdBy": "57469f3c71c8bf2479d225a6" } }],
res = results.map(function (a) {
var o = { _id: a._id };
["info", "type", "date", "createdBy"].forEach(function (k) {
o[k] = a._source[k];
});
return o;
});
console.log(res);
I had the same requirement, and the below solution worked best for me.
let users = [
{
"_id": "5ead7783ed74d152f86de7b0",
"first_name": "User First name 1",
"last_name": "User Last name 1",
"email": "user1#example.com",
"phone": 9587788888
},
{
"_id": "5ead7b780d4bc43fd0ef92e7",
"first_name": "User FIRST name 1",
"last_name": "User LAST name 1",
"email": "user2#example.com",
"phone": 9587788888
}
];
users = users.map(user => _.pick(user,['_id','first_name']))
console.log(users)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
var results = [{
_type: "MyType",
_id: "57623535a44b8f1417740a13",
_source: {
info: {
year: 2010,
number: "string",
},
type: "stolen",
date: "2016-06-16T00:00:00",
createdBy: "57469f3c71c8bf2479d225a6"
}
}];
var rootProperty = ['_id']
var innerProperty = '_source'
var myArray = _.map(results, result => _(result)
.pick(rootProperty)
.assign(_.result(result, innerProperty))
.value()
)
console.log(myArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You can map() the result and have each item assign() the _id key-value in an object toegether with the _source object.
results = _.map(results, item => _.assign(
{ _id: item._id },
item._source
));
var results = [{
"_type": "MyType",
"_id": "57623535a44b8f1417740a13",
"_source": {
"info": {
"year": 2010,
"number": "string",
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}
}];
results = _.map(results, item => _.assign(
{ _id: item._id },
item._source
));
document.write('<pre>' + JSON.stringify(results, 0, 4) + '</pre>');
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
You may also choose to write this in plain JS:
result = results.map(item => Object.assign(
{ _id: item._id }, item._source
));
var results = [{
"_type": "MyType",
"_id": "57623535a44b8f1417740a13",
"_source": {
"info": {
"year": 2010,
"number": "string",
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}
}];
result = results.map(item => Object.assign(
{ _id: item._id }, item._source
));
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
To correctly fulfill the OP's question and for even more complex requirements, the application of a schema and a small lodash mixin is invaluable.
The JavaScript is a little ugly, but it looks swell in CoffeeScript (yes, that was a thing once). The compiled JavaScript is hidden beneath.
_.mixin mapGet: (obj, schema) ->
result = for row in input
row_result = {}
for key, value of schema
row_result[key] = _.get(row, value)
row_result
_.mixin({ mapGet: function(obj, schema) {
var key, result, row, row_result, value;
return result = (function() {
var i, len, results;
results = [];
for (i = 0, len = input.length; i < len; i++) {
row = input[i];
row_result = {};
for (key in schema) {
value = schema[key];
row_result[key] = _.get(row, value);
}
results.push(row_result);
}
return results;
})();
}});
/* The remainer is just the proof/usage example */
var expected, input, schema;
input = [{
"_type": "MyType",
"_id": "57623535a44b8f1417740a13",
"_source": {
"info": {
"year": 2010,
"number": "string"
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}}];
expected = [{
"_id": "57623535a44b8f1417740a13",
"info": {
"year": 2010,
"number": "string"
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}];
schema = {
"_id": "_id",
"info": "_source.info",
"type": "_source.type",
"date": "_source.date",
"createdBy": "_source.createdBy"
};
console.log('expected result: ' + JSON.stringify(expected, 0, 4));
console.log('actual result: ' + JSON.stringify(_.mapGet(input, schema), 0, 4));
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>
Usage:
schema = {
"_id" : "_id",
"info" : "_source.info",
"type" : "_source.type",
"date" : "_source.date",
"createdBy": "_source.createdBy",
}
_.mapGet(input, schema)
Resultant output:
[{
"_id": "57623535a44b8f1417740a13",
"info": {
"year": 2010,
"number": "string"
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}]
Note: Complex schema can be more easily described if the source JSON is first converted to a flat, dotted, representation via:
jq [leaf_paths as $path | {"key":$path | join("."), "value":getpath($path) }] |from_entries'