The post may seem lengthy but it’s quite easy to follow, if not, I will add more details
I have criteria
array which that looks like :
let criteria = [ "and", { "Collection": "persons", "Property": "phone", "operator": "eq", "operatorValue": "$p:phone" }, { "Collection": "persondetails", "Property": "country", "operator": "eq", "operatorValue": "$p:country" }, ["or", { "Collection": "persons", "Property": "city", "operator": "eq", "operatorValue": "$p:city" }] ]
Characteristics of criteria
:
- It could have nested arrays.
- First item array (or nested array) is always going to be either “and” or “or”
- Second item onwards in array, item could be either an object with this specific structure
{ "Collection": "persons", "Property": "phone", "operator": "eq", "operatorValue": "$p:phone" }
or it could be an array like:
["or", { "Collection": "persons", "Property": "city", "operator": "eq", "operatorValue": "$p:city" }]
- Object is never going to be nested object
There is also a parameters
object:
let parameters = {phone:"23138213", "country": "Russia", "city":"york"}
The aim is to recursively traverse through all the operatorValue
properties in the criteria
array and if you encounter value such as $p:phone
, it is to be replaced by whatever parameters["phone"]
evaluate to.
EXPECTED OUTPUT:
[ "and", { "Collection": "persons", "Property": "phone", "operator": "eq", "operatorValue": "23138213" }, { "Collection": "persondetails", "Property": "country", "operator": "eq", "operatorValue": "Russia" }, ["or", { "Collection": "persons", "Property": "city", "operator": "eq", "operatorValue": "york" }] ]
I was able to recursively traverse through the array. The only problem is that I can’t figure out how to modify the original criteria
variable.
Please see the line 43 in repl. item[1]=parameters[item[1].split('$p:')[1]]
I understand why it won’t modify the criteria, its because item over here is a different variable in different scope altogether.
Failed Attempt :
function traverse(obj,parameters){ obj.forEach((item,index)=>{ if( typeof item == 'string' ){ //do nothing } else if( !(item instanceof Array)){ Object.entries(item).forEach((item,index)=>{ if( item[1] instanceof Array){ traverse(item,parameters); }else{ if(item[1].startsWith('$p:')){ item[1]=parameters[item[1].split('$p:')[1]] //values dont get replaced for obvious reason console.log(item[1]) } } }) } else if( item instanceof Array){ traverse(item,parameters); } }) } traverse(criteria,parameters) console.log(criteria)
How do I go about solving this problem?
Advertisement
Answer
You could simplify your function. You don’t need to loop through the entries of the object. You also don’t need to split
the operationValue
. That mapping key of parameters
is present in the Property
key.
- Loop through each item in the array and check if the item is an
Array
. - If yes, recursively call
traverse
on the item. - If it is an object, update its
operatorValue
property withparameters[val.Property]
function traverse(arr, parameters) { for (const item of arr) { if (Array.isArray(item)) traverse(item, parameters) else if (typeof item === 'object') item.operatorValue = parameters[item.Property] } return arr } let criteria=["and",{Collection:"persons",Property:"phone",operator:"eq",operatorValue:"$p:phone"},{Collection:"persondetails",Property:"country",operator:"eq",operatorValue:"$p:country"},["or",{Collection:"persons",Property:"city",operator:"eq",operatorValue:"$p:city"}]], parameters = {phone:"23138213", "country": "Russia", "city":"york"}; console.log(traverse(criteria, parameters))