按值访问嵌套 JSON 数组

Access by value on nested JSON arrays

我是 JavaScript 的新手,我真的迷路了。以下是 PHP json_encode() 生成的一些数据(并且仅限于最相关的键):

[
  {
    "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":""
  }
]

我需要访问 priceprice_prefix 值(在 JavaScript 中)知道 product_option_idproduct_option_value_id

我该怎么做?我应该去循环吗?

更新:

感谢您的回复。除非我遗漏了什么,否则 in my case arrays (as ugly as they may be…) are much more efficient 似乎比所有建议的解决方案都好(我将尝试另一种方法,使用 PHP 格式化符合我需求的 JSON 对象,而不是使用 "default" 一个,但这是题外话)。尽管我不喜欢添加库,而且它比大多数其他解决方案都要慢一些,但我还是会接受 Matt 的解决方案,因为就 JSON 访问而言,它似乎确实让生活变得更轻松。但需要注意的是,Yeldard 和 Barmar 的(几乎是克隆的)解决方案比其他命题更快。

你可以这样做

    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;
    }

}

应该这样做:

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];
}  

如果存在匹配项,它将被分配给 matchingInner

是的,您需要枚举数组并找到您的项目:

这是输出 price_prefixprice 产品 product_option_id = 228 和 product_option_value_id = 19 的工作代码。您可以用自己的值替换这些值.

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.

使用嵌套循环搜索主数组和子数组,寻找匹配的元素。

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

在 returned 数组上使用 filter on the main array to grab the right object, filter again on the option_value_id, then map 以获得单个 price/prefix 对象。 mapfilter 都是 return 数组,这就是为什么您看到代码在几个地方拾取第一个元素 ([0]) 的原因。

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

执行以下操作:

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] || [];
}

用法:

getProductValues(data, 229, 51)

结果:

{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 取决于您的 ID 是否唯一。

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

对于更复杂的数据选择,您可能需要查看 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
)