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))