Search code examples
javascriptarraysecmascript-6ecmascript-5

Manipulating a complex object based on an input array


I have an complex object and based on an input array I need to modify properties inside of this complex object. Illustration is shown below. I need to group them based on field values and then add them to the "or" array of objects(if field value is same). If not same,directly add it to the "and" array of objects. Need to read each field from the input array,and check if this is present inside "filter" of "filterObj" and if present add it to "and" else add it to the "or"

The format of both is shown below

//This is the source object where I need to add the below "arr" based on grouping

let filterObj = {
      "feature": "test",
      "filter": {
                 "and": [
                          { "field": "field1","value": "1"}
                        ]
                }
};

//This array needs to be added to above object by grouping based on field
let obj = [
             {"field" : "field1","value": "2"},
             {"field" : "field2","value": "3"},
             {"field" : "field2","value": "4"},
             {"field" : "field3","value" : "5"}
          ]


I want the output to be of following format:

var result = {
              "feature": "test",
              "filter": {
                 "and": [
                          {
                           "or" : [
                                    {"field": "field1","value": "1"},
                                    {"field": "field1", "value": "2"}
                                  ]                      
                          },
                          {
                            "or" : [
                                     {"field": "field2","value": "3"},
                                     {"field": "field2","value": "4"},
                                   ]                      
                          },
                          {  "field": "field3", "value": "5"}
                  ]
              } 
}

// The method that I have tried

filterObj.filter.and.or(...obj) ;// Does not work 



Solution

  • You could collect all same fields by a grouping and assign the values from grouping to and property.

    var filterObj = { feature: "test", filter: { and: [{ field: "field1", value: "1" }] } },
        obj = [{ field: "field1", value: "2" }, { field: "field2", value: "3" }, { field: "field2", value: "4" }, { field: "field3", value: "5" }],
        groups = obj.reduce(
            (r, o) => {
                if (r[o.field]) {
                    if (!('or' in r[o.field])) r[o.field] = { or: [r[o.field]] };
                    r[o.field].or.push(o);
                } else {
                    r[o.field] = o;
                }
                return r;
            },
            (filterObj.filter.and || []).reduce((r, o) => {
                r['or' in o ? o.or[0].field : o.field] = o;
                return r;
            }, {}));
    
    filterObj.filter.and = Object.values(groups);
    
    console.log(filterObj);
    .as-console-wrapper { max-height: 100% !important; top: 0; }