简体   繁体   中英

Access by value on nested JSON arrays

I'm new to JavaScript and I'm really lost here. Here is some data produced by PHP json_encode() (and limited to most pertinent keys) :

[
  {
    "product_option_id":"229",
    "product_option_value":
    [
      {
        "product_option_value_id":"21",
        "option_value_id":"51",
        "price":"1,22 €",
        "price_prefix":"+"
      },
      {
        "product_option_value_id":"22",
        "option_value_id":"52",
        "price":false,
        "price_prefix":"+"
      },
      {
        "product_option_value_id":"23",
        "option_value_id":"53",
        "price":"2,42 €",
        "price_prefix":"+"
      }
    ],
    "option_id":"14",
    "type":"radio",
    "value":""
  },
  {
    "product_option_id":"228",
    "product_option_value":
    [
      {
        "product_option_value_id":"19",
        "option_value_id":"49",
        "price":"1,22 €",
        "price_prefix":"+"
      },
      {
        "product_option_value_id":"20",
        "option_value_id":"50",
        "price":"2,42 €",
        "price_prefix":"+"
      }
    ],
    "option_id":"13",
    "type":"select",
    "value":""
  }
]

I need to access price and price_prefix values (in JavaScript) knowing product_option_id and product_option_value_id .

How do I do that ? Should I go for a loop ?

Update :

Thanks for replies. Unless I missed something, it appears that in my case arrays (as ugly as they may be…) are much more efficient than all the proposed solutions (I'll try another approach, formatting a JSON object corresponding to my needs with PHP rather than using the "default" one, but it's off topic here). Though I'm not fond of adding libraries and it's a bit slower than most other solutions, I'll accept Matt's solution because it really seems to make life easier as far as JSON access is concerned. But it should be noted that Yeldard and Barmar's (almost cloned) solutions are faster than other propositions.

you can do like this

    for(var i in jsonData) {
    var item = jsonData[i];
    if(item.product_option_id == 229) {
        for(var j in item.product_option_value){
            var item1 = item.product_option_value[j];
            if(item1.product_option_value_id == 21) {
                //your item here
                break;
            }
        }
       break;
    }

}

This should do it:

var productOptionId = 229;
var productOptionValue = 22;

var matchingOuter = yourData.filter(function(i){
    return i.product_option_id === productOptionId; 
})[0];

if (matchingOuter) {
    var matchingInner = matchingOuter.product_option_value.filter(function(i){
        return i.product_option_value === productOptionValue;
    })[0];
}  

If a matching item exists it will be assigned to matchingInner

Use nested loops to search through the main array and the sub-arrays, looking for the matching element.

function find_product(product_option_id, product_option_value_id) {
    for (var i = 0; i < products.length; i++) {
        var product = products[i];
        if (product.product_option_id == product_option_id) {
            for (var j = 0; j < product.product_option_value.length; j++) {
                var value = product.product_option_value[j];
                if (value.product_option_value_id == product_option_value_id) {
                    return { price: value.price, price_prefix: value.price_prefix }
                }
            }
        }
    }
}

Use filter on the main array to grab the right object, filter again on the option_value_id, then map on the returned array to get a single price/prefix object. map and filter both return arrays which is why you see the code picking up the first element ( [0] ) in a couple of places.

function getData(data, options) {
    return data.filter(function (product) {
      return product.product_option_id === options.id;
    })[0].product_option_value.filter(function (details) {
       return details.product_option_value_id === options.optionId;
    }).map(function(el) {
      return { price: el.price, prefix: el.price_prefix }
    })[0];
}

getData(data, { id: '229', optionId: '23' }); // { price: "2,42 €", prefix: "+" }

DEMO

Following would do:

function getProductValues(products, product_option_id, product_option_value_id) {
    if (!product_option_id || !product_option_value_id) {
        return;
    }

    return products.filter(function(product) {
        return +product.product_option_id === product_option_id;
    }).map(function (product) {
        var option_values = product.product_option_value;
        return option_values.filter(function (option) {
            return +option.option_value_id === product_option_value_id;
        })[0] || [];
    })[0] || [];
}

Usage:

getProductValues(data, 229, 51)

Result:

{product_option_value_id: "21", option_value_id: "51", price: "1,22 €", price_prefix: "+"}

lodash would make this easier and neater. It provides _.find or _.filter depending on if your id's are unique or not.

var record = _.find( data_structure, {
  "product_option_id": "229"
})
if ( !record ) throw new Error("Record not found");

var value = _.find( record.product_option_value, {
  "product_option_value_id":"22" 
})
if ( !value ) throw new Error("Value not found");

console.log( "price[%s] prefix[%s]", value.price, value.price_prefix )

Demo

For more complex data selection, you might want to look at sift.js . It's based on mongodb's query system .

var records = sift({ 
    "product_option_id": "229", 
    "product_option_value": {
      $elemMatch: {
        "product_option_value_id": "22"  
      }
    }
  },
  data_structure
)

Yes, you need to enumerate through the array and find your items:

Here is the working code which outputs price_prefix and price of product with product_option_id = 228 and product_option_value_id = 19. You can replace these values with your own.

for (var i = 0; i < obj.length; i++) // Enumerate through array
{
    var item = obj[i];
    if (item.product_option_id === "228") // Filtering items by product_option_id
    {
        // When necessary product_option_id found
        for (var j = 0; j < item.product_option_value.length; j++) // Enumerate through its products
        {
            var productItem = item.product_option_value[j]; 
            if (productItem.product_option_value_id === "19") // Filtering by product_option_value_id
            {
                // here it is. productItem is found! do whatever you want with it
                alert(productItem.price_prefix + " " + productItem.price);
            }
        }
    }
}

Working JSFiddle demo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM