Serialize object of params to url - javascript

We have input like this
const params = {
id: 1,
filters: {
price: {
min: 101,
max: 300
}
},
sorters: {
sortBy: 'price',
order: 'desc'
}
}
and we want output to look like this id=1&min=101&max=300&sortBy=price&order=desc.
Object is nested. If we have object with just 1 level (no object within objects) then we could simply do
for (const [key, value] of Object.entries(object1)) {
arr.push(`${key}=${value}`);
}
then probably .join array with &. But here in this case this is not enough. My first though was to just inner this for loops like this:
const paramsStringify = (paramsObject) => {
const arr = []
for (const [key, value] of Object.entries(paramsObject)) {
if(typeof value === 'object') {
for (const [key2, value2] of Object.entries(value)) {
if(typeof value2 === 'object') {
for (const [key3, value3] of Object.entries(value2)) {
console.log('3rd lvl', `${key3}: ${value3}`);
arr.push(`${key3}=${value3}`)
}
} else {
console.log('2nd lvl', `${key2}: ${value2}`);
arr.push(`${key2}=${value2}`)
}
}
} else {
console.log('1st lvl', `${key}: ${value}`);
arr.push(`${key}=${value}`)
}
}
console.log('arr', arr.join('&'))
}
this is working fine but code look awful to me. I nested it three times, if I would have even more nested objects I would need to put another for loop there. But the pattern is same for each level of objects. Can I somehow refactor it so it would work even if I have input with 7 nested objects?

You could use a URLSearchParams object and recursively append key value pairs to it. This will automatically encode values.
const params = {
id: 1,
filters: { price: { min: 101, max: 300 } },
sorters: { sortBy: "price", order: "desc" }
}
function getParam(o, searchParam = new URLSearchParams) {
Object.entries(o).forEach(([k, v]) => {
if (v !== null && typeof v === 'object')
getParam(v, searchParam)
else
searchParam.append(k, v)
})
return searchParam
}
const searchParam = getParam(params);
console.log(
searchParam.toString()
)

const params = {
id: 1,
filters: {
price: {
min: 101,
max: 300
}
},
sorters: {
sortBy: 'price',
order: 'desc'
}
}
function add(a, o) {
for (const [key, value] of Object.entries(o)) {
if (typeof value === 'object') add(a, value); // recursion
else a.push(`${key}=${value}`); // only if value not-an-object
}
return a;
}
console.log(add([], params).join("&"))
This is a simple recursive version. You will probably have to tune it if you want to support more complex structures (arrays, duplicate keys, ...)

Assuming your object adheres to your example, use a URLSearchParams object and avoid recursion using a regex
const params = {
id: 1,
filters: {
price: {
min: 101,
max: 300
}
},
sorters: {
sortBy: 'price',
order: 'desc'
}
}
const js = JSON.stringify(params);
const re = /"(\w+)":[^\{]?"?(\w+)"?/g
const usp = new URLSearchParams();
js.match(re).forEach(str => {
const [key,val] = str.split(":");
usp.set(key.replace(/"/g,""),val.replace(/"/g,""))
})
console.log(usp.toString())

You need to create a recursive function if you don't want to program the same logic for each nested object. See https://www.javascripttutorial.net/javascript-recursive-function/ for more information about recursive functions.

Related

Sort deeply nested objects alphabetically by keys

We are using vue-i18n and maintain our messages within an js variable. This leads to deeply nested objects or key/value pairs.
const messages = {
en: {
message: {
page1: {
title: "Some title",
button: {
title: "Foo",
},
subpage: {
...
}
},
...
},
},
de: {...},
};
As u can see, without an appropriate sorting this file will be really confusing. My idea is to sort the whole file alphabetically by keys.
Is there an algorithm/code that can be used for this? Or do I have to write it myself?
You can do some recursivity like :
I used the following answer to write the order function
const order = (unordered) => Object.keys(unordered).sort().reduce(
(obj, key) => {
obj[key] = unordered[key];
return obj;
}, {}
);
const message = {
fr: {
message: "Bonjour",
a: 1
},
en: {
message: "Hello",
a: {
c: 1,
b: 2
}
},
es: "Hola"
}
const sortObjectDeeply = (object) => {
for (let [key, value] of Object.entries(object)) {
if (typeof(value) === "object") {
object[key] = sortObjectDeeply(value)
}
}
return order(object)
}
console.log(sortObjectDeeply(message))

Recursively update nested object values for specific keys based on another object

*** UPDATED object structure ***
I'd like to update recursively the property values of mainObject from the properties that exist in updatingObject.
let mainObject = {
age: 24,
isMarried: false,
pets: {
dog: {
name: "Juniper",
age: 3
},
cat: {
name: "Spasia",
age: 7
}
},
hobbies: {
mountainRelated: ["hiking", "snowboarding"]
}
}
let updatingObject = {
pets: {
cat: {
age: 8
}
}
}
I've added a Codepen link to the problem below: what I still have to do is to find the correct properties to be updated (for example the "age" property is common for more objects).
TL;DR: cat age should be 8 in the mainObject
https://codepen.io/Dragosb/pen/bGwypKz?editors=0012
You can traverse in sync
let mainObject = {
age: 24,
isMarried: false,
pets: {
dog: { name: "Juniper", age: 3 },
cat: { name: "Spasia", age: 7 }
},
hobbies: {
mountainRelated: ["hiking", "snowboarding"]
}
}
let updatingObject = {
pets: {
cat: {
age: 8,
name:'gabriele'
}
}
}
function updateObject(target, update){
// for each key/value pair in update object
for (const [key,value] of Object.entries(update)){
// if target has the relevant key and
// the type in target and update is the same
if (target.hasOwnProperty(key) && typeof(value) === typeof(target[key])){
// update value if string,number or boolean
if (['string','number','boolean'].includes(typeof value) || Array.isArray(value)){
target[key] = value;
} else {
// if type is object then go one level deeper
if (typeof value === 'object'){
updateObject(target[key], value)
}
}
}
}
}
updateObject(mainObject,updatingObject)
console.log(mainObject);
We can write a function that does this without mutating the original object, in a fairly simple manner. This merge function breaks the original and update objects into key-value pairs, then keeps all those whose keys are only in one of them, and, for those in both, if both values are objects recursively calling merge on them, otherwise choosing the update value. The resulting key-value pairs are then put back into an object.
Here is an implementation:
const merge = (a, b) => Object .fromEntries ([
... Object .entries (a) .filter (([k]) => !(k in b)),
... Object .entries (b) .filter (([k]) => !(k in a)),
... Object. entries (b) .filter (([k]) => (k in a)) .map (([k, v]) =>
[k, Object (v) === v && Object (a [k]) === a [k] ? merge (a [k], v) : v]
),
])
const mainObject = {age: 24, isMarried: false, pets: {dog: { name: "Juniper", age: 3 }, cat: { name: "Spasia", age: 7 }}, hobbies: {mountainRelated: ["hiking", "snowboarding"]}}
const updatingObject = {pets: {cat: {age: 8, name:'gabriele'}}}
console .log (merge (mainObject, updatingObject))
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that while the resulting object is a new one, we use a form of structural sharing between this and the input objects. For instance, if you push 'hangliding' onto the array hobbies.mountainRelated in the resulting object, we will update mainObject values as well. While we could change this behavior, it helps reduce memory consumption, so I wouldn't do so without good reason.
Note that this does not try to deal with more complicated scenarios, such as cyclic objects. It also does not do anything to work with arrays. Arrays add numerous complexities, and if you need them, I would suggest looking at the equivalent functions in a library such as Ramda's mergeDeepRight (disclaimer: I'm an author) or lodash's merge, or dedicated tools like deepmerge.
The below approach solves the problem by first constructing the access path to the property of an object, then access and modify the mainObject according to the access path constructed from the updatingObject.
let mainObject = {
age: 24,
isMarried: false,
pets: {
dog: {
name: 'Juniper',
age: 3,
},
cat: {
name: 'Spasia',
age: 7,
},
},
hobbies: {
mountainRelated: ['hiking', 'snowboarding'],
},
};
let updatingObject = {
pets: {
cat: {
age: 8,
},
},
hobbies: {
mountainRelated: ['biking'],
none: 'not updated',
},
};
function updateGivenObject(mainObject, updatingObject) {
const mainObjPaths = [];
const updateObjPaths = [];
buildPath(mainObject, mainObjPaths);
buildPath(updatingObject, updateObjPaths);
console.log('mainObjPaths:', mainObjPaths);
console.log('updateObjPaths :', updateObjPaths );
updateObjPaths.forEach(path => {
const newValue = getPropByPath(updatingObject, path);
setPropByPath(mainObject, path, newValue);
});
}
function buildPath(obj, accumulatedPaths, currentPaths = []) {
Object.keys(obj).map(key => {
if (typeof obj[key] !== 'object') {
accumulatedPaths.push([...currentPaths, key].join('.'));
} else {
buildPath(obj[key], accumulatedPaths, [...currentPaths, key]);
}
});
}
function getPropByPath(obj, path) {
const pathArr = path.split('.');
let value = obj;
pathArr.forEach(key => {
value = value[key];
});
return value;
}
function setPropByPath(obj, path, newValue) {
const pathArr = path.split('.');
let value = obj;
pathArr.forEach((key, idx) => {
if (value[key] === undefined) {
return;
}
if (idx === pathArr.length - 1) {
value[key] = newValue;
} else {
value = value[key];
}
});
return value;
}
updateGivenObject(mainObject, updatingObject);
console.log(mainObject);
console.log(mainObject.pets.cat.age);
console.log(mainObject.hobbies.mountainRelated[0]);
console.log(mainObject.hobbies.none);
However, the above algorithm depends heavily on shared mutable state and should be careful about it.

JavaScript - build a tree data structure recursively

I have a function called tree, which takes array of objects (as data fields from a database) and array of strings for keys. The function loops through rowsArray and recursively creates object with nested properties based on keyArray.
const tree = (rowsArray, keysArray) => {
return rows.reduce((acc, row) => {
const groupBy = (row, keys,) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = {...groupBy(row, keys), ...acc};
return acc;
}, {});
}
The data is following:
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
When I log the result, I get:
/*
// actual output
{
Financial: {
Forecasts: {
General: [Array]
}
}
}
Whereas, I would like to get following:
// expected
{
Financial: {
Forecasts: {
General: [Array]
},
HR: {
Headcount: [Array]
}
}
}
*/
The problem is, that acc variable in main function gets overridden and I get new object, instead of accumulative and I am not quite sure how to recursively build this object. I tried to pass instances of acc to groupBy function (to remember previous results), but no luck.
Do you have any idea how I could rewrite tree function or groupBy function to accomplish my goal? Thanks!
You could do it like this:
function tree(rows, keys) {
return rows.reduce( (acc, row) => {
keys.reduce( (parent, key, i) =>
parent[row[key]] = parent[row[key]] || (i === keys.length - 1 ? [row] : {})
, acc);
return acc;
}, {});
}
const data = [{ID: 1,Main: "Financial",Sub: "Forecasts",Detail: "General"}, {ID: 2,Main: "Financial",Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
Be aware that the spread syntax makes a shallow copy. Instead, in this solution, the accumulator is passed to the inner reduce. And so we actually merge the new row's hierarchical data into the accumulator on-the-spot.
The problem is your merge function is not deep. When you assign the values to the accumulator you overwrite existing properties - in this case Financial.
I included a deep merge function from here and now it works.
I also fixed some reference errors you had:
rows => rowsArray
keys = keysArray
// deep merge function
function merge(current, update) {
Object.keys(update).forEach(function(key) {
// if update[key] exist, and it's not a string or array,
// we go in one level deeper
if (current.hasOwnProperty(key) &&
typeof current[key] === 'object' &&
!(current[key] instanceof Array)) {
merge(current[key], update[key]);
// if update[key] doesn't exist in current, or it's a string
// or array, then assign/overwrite current[key] to update[key]
} else {
current[key] = update[key];
}
});
return current;
}
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
const groupBy = (row, keys, ) => {
const [first, ...rest] = keys;
if (!first) return [row];
return {
[row[first]]: groupBy(row, rest),
}
};
acc = merge(groupBy(row, keysArray), acc);
return acc;
}, {});
}
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
You could iterate the keys and take either an object for not the last key or an array for the last key and push then the data to the array.
const tree = (rowsArray, keysArray) => {
return rowsArray.reduce((acc, row) => {
keysArray
.map(k => row[k])
.reduce((o, k, i, { length }) => o[k] = o[k] || (i + 1 === length ? []: {}), acc)
.push(row);
return acc;
}, {});
}
const data = [{ ID: 1, Main: "Financial", Sub: "Forecasts", Detail: "General" }, { ID: 2, Main: "Financial", Sub: "HR", Detail: "Headcount" }];
const result1 = tree(data, ["Main", "Sub", "Detail"]);
console.log(result1);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can iterate over the data and created a unique key based on the keys provided and then recursively generate the output structure by deep cloning.
const data = [{
ID: 1,
Main: "Financial",
Sub: "Forecasts",
Detail: "General"
}, {
ID: 2,
Main: "Financial",
Sub: "HR",
Detail: "Headcount"
}];
function generateKey(keys,json){
return keys.reduce(function(o,i){
o += json[i] + "_";
return o;
},'');
}
function merge(first,second){
for(var i in second){
if(!first.hasOwnProperty(i)){
first[i] = second[i];
}else{
first[i] = merge(first[i],second[i]);
}
}
return first;
}
function generateTree(input,keys){
let values = input.reduce(function(o,i){
var key = generateKey(keys,i);
if(!o.hasOwnProperty(key)){
o[key] = [];
}
o[key].push(i);
return o;
},{});
return Object.keys(values).reduce(function(o,i){
var valueKeys = i.split('_');
var oo = {};
for(var index = valueKeys.length -2; index >=0 ;index--){
var out = {};
if(index === valueKeys.length -2){
out[valueKeys[index]] = values[i];
}else{
out[valueKeys[index]] = oo;
}
oo = out;
}
o = merge(o,oo);
return o;
},{});
}
console.log(generateTree(data,["Main", "Sub", "Detail"]));
jsFiddle Demo - https://jsfiddle.net/6jots8Lc/

JS/TS how to iterate thru object array and change values

consider the following array.
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
What is the best way to build a function which can do the following goals?
1) will set all members to false
2) set chosen member to true ( passed as a parameter )
Absent more specific requirements, this is a bit of a choose-your-own-adventure.
(Note: For brevity this code uses ES6 computed property names and destructuring assignment and ES2018 object spread syntax, all of which can be transpiled by TypeScript.)
If each object has exactly one key
...and you want to mutate the original array and objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
const [key] = Object.keys(obj);
obj[key] = key === selectedKey;
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const [key] = Object.keys(obj);
newObjects.push({ [key]: key === selectedKey });
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [ { vehicle: true }, { userAssignment: false }, { relations: false } ];
function selectKey(objects, selectedKey) {
return objects.map(obj => {
const [key] = Object.keys(obj);
return { [key]: key === selectedKey };
});
}
console.log(selectKey(objects, 'userAssignment'))
If the objects can have more than one key
...and you want to mutate the original array and objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
for (let obj of objects) {
for (let key of Object.keys(obj)) {
obj[key] = key === selectedKey;
}
}
return objects;
}
selectKey(objects, 'userAssignment');
console.log(objects);
...and you want a new array of new objects
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
const newObjects = [];
for (let obj of objects) {
const newObj = {};
for (let key of Object.keys(obj)) {
newObj[key] = key === selectedKey;
}
newObjects.push(newObj);
}
return newObjects;
}
console.log(selectKey(objects, 'userAssignment'))
...but you really like functional style
const objects = [
{ vehicle: true, relations: false },
{ userAssignment: false, vehicle: true },
{ relations: false, userAssignment: false },
];
function selectKey(objects, selectedKey) {
return objects.map(obj =>
Object.keys(obj).reduce((newObj, key) =>
({ ...newObj, [key]: key === selectedKey }),
{}
)
);
}
console.log(selectKey(objects, 'userAssignment'))
You can iterate the array with Array.forEach(), get the key using Object.keys(), compare to the selected key, and set the value accordingly:
const routingButtonsHighlighter = [{vehicle: true}, {userAssignment: false}, {relations: false}];
const select = (arr, selectedKey) =>
arr.forEach((o) => {
const key = Object.keys(o)[0];
o[key] = key === selectedKey;
});
select(routingButtonsHighlighter, 'userAssignment');
console.log(routingButtonsHighlighter);
Creating a method for something like this would be highly specialized, so to abstract it, I've decided to write it like this:
function arrayFlagSinglePropertyTrue(key, arrayofobjects) {
for (let i in arrayofobjects) {
let keys = Object.keys(arrayofobjects[i]);
if (keys[0] == key) {
arrayofobjects[i][keys[0]] = true;
} else {
arrayofobjects[i][keys[0]] = false;
}
}
return arrayofobjects;
}
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
console.log(arrayFlagSinglePropertyTrue("relations", routingButtonsHighlighter));
Although this will get what you require done, its highly specialized and only works if the objects in the array contain one property or at the very least the first property in the object itself is the one you want to set to flag.
Edit: Some advice:
Uniformity in lists helps avoid the issue you have. By structuring your objects with uniform property names and then acting on the values themselves, you no longer require the use of specialized functions or code in order to modify it. At this point you can rely on fundamental programming logic to change the properties efficiently.
If you get the list from some external source and have no control over it, then you may need to either reorganize it yourself. If you can't then making specialized functions/codes is your last resort.
If possible, take something like this:
routingButtonsHighlighter = [
{vehicle: true},
{userAssignment: false},
{relations: false}
];
Organize it into something like this where the actual object properties are uniform:
let betterStructureObject = [
{ propertyName: "vehicle", status: true },
{ propertyName: "userAssignment", status: false },
{ propertyName: "vehicle", status: false },
]
So you can easily loop over it and not have to worry about writing specialized code.
for (let i in betterStructureObject) {
if (betterStructureObject[i].propertyName == "vehicle")
betterStructureObject[i].status = true;
else betterStructureObject[i].status = false;
}

Recursively collect values for property using lodash

For a nested complex object or array, I would like to collect all values for a given property name. Example:
var structure = {
name: 'alpha',
array: [
{ name: 'beta' },
{ name: 'gamma' }
],
object: {
name: 'delta',
array: [
{ name: 'epsilon' }
]
}
};
// expected result: [ 'alpha', 'beta', 'gamma', 'delta', 'epsilon' ]
It's obvious how to achieve this using plain JS, but: Is there any elegant, concise approach using lodash?
[edit] Current variant below. Nicer solutions welcome!
function getPropertyRecursive(obj, property) {
var values = [];
_.each(obj, function(value, key) {
if (key === property) {
values.push(value);
} else if (_.isObject(value)) {
values = values.concat(getPropertyRecursive(value, property));
}
});
return values;
}
This can be done elegantly with the following mixin, which is a recursive version of _.toPairs:
_.mixin({
toPairsDeep: obj => _.flatMap(
_.toPairs(obj), ([k, v]) =>
_.isObjectLike(v) ? _.toPairsDeep(v) : [[k, v]])
});
then to get the result you want:
result = _(structure)
.toPairsDeep()
.map(1)
.value()
If there are scalar properties other than name, you'll have to filter them out:
result = _(structure)
.toPairsDeep()
.filter(([k, v]) => k === 'name')
.map(1)
.value()
There's no Lodash/Underscore function that I know if that will do what you're looking for.
So what are you looking to do? Well, specifically you're looking to extract the values of all of the name properties out of a aggregate structure. How would we generalize that? In other words, if you were looking to add such functionality to Lodash/Underscore, how would you reframe the problem? After all, most people don't want to get the values of the name properties. You could create a generic function where you supply the name of the property you want, but...thinking even more abstractly than that, what you really want to do is visit all of the nodes in a aggregate structure and do something with them. If we consider aggregate structures in JavaScript as generic trees, we can take a recursive approach using a depth-first walk:
function walk(o, f) {
f(o);
if(typeof o !== 'object') return;
if(Array.isArray(o))
return o.forEach(e => walk(e, f));
for(let prop in o) walk(o[prop], f);
}
Now we can do what you're looking for by walking the structure and adding things to an array:
const arr = [];
walk(structure, x => if(x !== undefined && x.name) arr.push(x.name));
This isn't quite functional enough for my tastes, though...there's a side effect on arr here. So an even better generic approach (IMO) would be to allow a context object to ride along (or an accumulator if you will, a la Array#reduce):
function walk(o, f, context) {
f(o, context);
if(typeof o !== 'object') return context;
if(Array.isArray(o)) return o.forEach(e => walk(e, f, context)), context;
for(let prop in o) walk(o[prop], f, context);
return context;
}
Now you can call it like this, side-effect free:
const arr = walk(structure, (x, context) => {
if(x !== undefined && x.name) context.push(x.name);
}, []);
Iterate the object recursively using _.reduce():
function getPropertyRecursive(obj, prop) {
return _.reduce(obj, function(result, value, key) {
if (key === prop) {
result.push(value);
} else if (_.isObjectLike(value)) {
return result.concat(getPropertyRecursive(value, prop));
}
return result;
}, []);
}
var structure = {
name: 'alpha',
array: [{
name: 'beta'
}, {
name: 'gamma'
}],
object: {
name: 'delta',
array: [{
name: 'epsilon'
}]
}
};
var result = getPropertyRecursive(structure, 'name');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.min.js"></script>
You could iterate the object and call it again for arrays or objects. Then get the wanted property.
'use strict';
function getProperty(object, key) {
function iter(a) {
var item = this ? this[a] : a;
if (this && a === key) {
return result.push(item);
}
if (Array.isArray(item)) {
return item.forEach(iter);
}
if (item !== null && typeof item === 'object') {
return Object.keys(item).forEach(iter, item);
}
}
var result = [];
Object.keys(object).forEach(iter, object);
return result;
}
var structure = { name: 'alpha', array: [{ name: 'beta' }, { name: 'gamma' }], object: { name: 'delta', array: [{ name: 'epsilon' }] } };
console.log(getProperty(structure,'name'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Based on the answer ( https://stackoverflow.com/a/39822193/3443096 ) , here's another idea for mixin:
_.mixin({
extractLeaves: (obj, filter, subnode, subpathKey, rootPath, pathSeparator) => {
var filterKv = _(filter).toPairs().flatMap().value()
var arr = _.isArray(obj) ? obj : [obj]
return _.flatMap(arr, (v, k) => {
if (v[filterKv[0]] === filterKv[1]) {
var vClone = _.clone(v)
delete vClone[subnode]
vClone._absolutePath = rootPath + pathSeparator + vClone[subpathKey]
return vClone
} else {
var newRootPath = rootPath
if (_.isArray(obj)) {
newRootPath = rootPath + pathSeparator + v[subpathKey]
}
return _.extractLeaves(
v[subnode], filter, subnode,
subpathKey, newRootPath, pathSeparator
)
}
})
}
});
This work for this example JSON, where you want to extract leaf-nodes:
{
"name": "raka",
"type": "dir",
"children": [{
"name": "riki",
"type": "dir",
"children": [{
"name": "roko",
"type": "file"
}]
}]
}
Use it this way:
_.extractLeaves(result, {type: "file"}, "children", "name", "/myHome/raka", "/")
And you will get:
[
{
"name": "roko",
"type": "file",
"_absolutePath": "/myHome/raka/riki/roko"
}
]

Categories