0

I have product structure as shown below:

   product = {  
  "name":"MyXam",
  "layers":[  
    {  
      "countries":[  
        {  
          "countryId":"1",
          "countryName":"ABC"
        },
        {  
          "countryId":"2",
          "countryName":"XYZ"
        },
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    },
    {  
      "countries":[  
        {  
          "countryId":"5",
          "countryName":"LMN"
        },
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    }
  ]
}

And selected countries:

selCountries =    [  
  {  
    "countryId":"1"
  },
  {  
    "countryId":"3"
  }
]

Now I want to filter the product in such a way that it should contain countries only that are in selCountries.

The final product should be:

{  
  "name":"MyXam",
  "layers":[  
    {  
      "countries":[  
        {  
          "countryId":"1",
          "countryName":"ABC"
        },
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    },
    {  
      "countries":[  
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    }
  ]
}

I have tried the following using lodash but is not working:

_.filter(product.layers, _.flow(
      _.property('countries'),
      _.partialRight(_.some, selCountries)
  ));

As the product comes dynamically in my application. In some cases there is a possibility that some of the layers may have not countries. So the solution should handle this case also and should not break with undefined error.

Can any on help me, where I am going wrong?

4 Answers 4

2

You should not need lodash for that. Just filter based on ID. If for all layers, map/forEach on the layers and filter the countries.

const product = {  
  "name":"MyXam",
  "layers":[  
    {  
      "countries":[  
        {  
          "countryId":"1",
          "countryName":"ABC"
        },
        {  
          "countryId":"2",
          "countryName":"XYZ"
        },
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    }
  ]
}

const selCountries = [  
  {  
    "countryId":"1"
  },
  {  
    "countryId":"3"
  }
];

const indices = selCountries.map(e => e.countryId); // Just IDs plz.
product.layers.forEach(layer => {
   if (layer.countries == null)
       return;

   layer.countries = layer.countries.filter(e => 
       indices.some(i => i == e.countryId)
   );
});
console.log(product);

Sign up to request clarification or add additional context in comments.

4 Comments

As in my application the product comes dynamically and in some cases the layer may not have countries also, in that case the it is throwing error saying undefined of filter. Is there any simple way to handle this in your solution
@MadasuK: Probably add a null check before filtering. Changed the code to forEach (modifies layers in-place!). But don't you want to wait for the product to load?
Even then some times from server side response missing that countries property.
I would probably just set the property to an empty array if there are no results.
1

My answer's similar to 31piy's in that I extract out the ids from selCountries first, and then rebuild the object with the filtered results. It also checks whether there are countries in the layers array as per your recent comment.

product = {"name":"MyXam","layers":[{"countries":[{"countryId":"1","countryName":"ABC"},{"countryId":"2","countryName":"XYZ"},{"countryId":"3","countryName":"PQR"}]},{"countries":[{"countryId":"5","countryName":"LMN"},{"countryId":"3","countryName":"PQR"}]}]}
const selCountries=[{"countryId":"1"},{"countryId":"3"}];

if (product.layers.length) {
  const selCountriesArr = selCountries.map(el => el.countryId);
  const newLayers = product.layers.map(obj => {
    const countries = obj.countries.filter(el => selCountriesArr.includes(el.countryId));
    return { countries };
  });
  const filteredProduct = { ...product, layers: newLayers };
  console.log(filteredProduct);
}

2 Comments

Andy, it should work across all layers not at index 0, as in your solution product.layers[0]. Can we make it generic?
Well, I can only base my answer on the details in your question. Perhaps you could update your question with this new information so I can understand.
1

You can create a temporary array with the IDs of countries selected, and then filter the countries based on it. Note that it modifies the original object in-place.

let product = {
  "name": "MyXam",
  "layers": [{
    "countries": [{
        "countryId": "1",
        "countryName": "ABC"
      },
      {
        "countryId": "2",
        "countryName": "XYZ"
      },
      {
        "countryId": "3",
        "countryName": "PQR"
      }
    ]
  }]
};

let selCountries = [{
    "countryId": "1"
  },
  {
    "countryId": "3"
  }
];

// Extract the IDs
let selCountryIds = _.map(selCountries, 'countryId');

// Filter the countries based on IDs
product.layers[0].countries = _.filter(product.layers[0].countries, country => {
  return _.includes(selCountryIds, country.countryId);
});

console.log(product);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

1 Comment

It should work for all layers not just at index 0 as given in the solution product.layers[0]
1

Instead of using lodash, you can make use of Array.map and Array.filter to iterate through the array and filter the product as per the selected countries.

var product = {  
  "name":"MyXam",
  "layers":[  
    {  
      "countries":[  
        {  
          "countryId":"1",
          "countryName":"ABC"
        },
        {  
          "countryId":"2",
          "countryName":"XYZ"
        },
        {  
          "countryId":"3",
          "countryName":"PQR"
        }
      ]
    }
  ]
}


var selCountries =    [  
  {  
    "countryId":"1"
  },
  {  
    "countryId":"3"
  }
];

product.layers = product.layers.map(function (layer) {
  return layer.countries.filter(function (country) {
    return selCountries.some(function(selCountry) {
      return selCountry.countryId === country.countryId;
    });
  });
});

console.log(product);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.