JSON Get parent object from child object

Vivek Singh picture Vivek Singh · Feb 25, 2016 · Viewed 10.7k times · Source

How can I get discount value if brand_id=='983'.

Sample JSON:

{
     "prods": [
               {
            "info": {
                  "rate": 100
                    },
            "grocery": [
                     {
                      "brand": "A",
                      "brand_id": "983"
                     },
                     {
                      "brand": "B",
                      "brand_id": "253"
                     }
                     ],
             "discount": "20"
         }
     ]
}

What I have tried till now is

$.prods[*].grocery[?(@.brand_id=='983')]

This returns me list/array of matched objects. But I am not able to traverse back into the tree. Any help on this?

Answer

YSharp picture YSharp · Feb 26, 2016

Indeed, JSONPath isn't very good at that, so I tackled this kind of problem with my own small library; so, here's a fiddle for your example:

https://jsfiddle.net/YSharpLanguage/j9oetwnn/3

where:

var products = {
     "prods": [
        {
            "info": {
                  "rate": 85
                    },
            "grocery": [
                     {
                      "brand": "C",
                      "brand_id": "984"
                     },
                     {
                      "brand": "D",
                      "brand_id": "254"
                     }
                     ],
             "discount": "15"
        },
        {
            "info": {
                  "rate": 100
                    },
            "grocery": [
                     {
                      "brand": "A",
                      "brand_id": "983"
                     },
                     {
                      "brand": "B",
                      "brand_id": "253"
                     }
                     ],
             "discount": "20"
         }
     ]
};

function GroceryItem(obj) {
  return (typeof obj.brand === "string") && (typeof obj.brand_id === "string");
}

    // last parameter set to "true", to grab all the "GroceryItem" instances
    // at any depth:
var itemsAndDiscounts = [ products ].nodeset(GroceryItem, true).
    map(
      function(node) {
        var item = node.value, // node.value: the current "GroceryItem" (aka "$.prods[*].grocery[*]")

            discount = node.parent. // node.parent: the array of "GroceryItem" (aka "$.prods[*].grocery")
                       parent. // node.parent.parent: the product (aka "$.prods[*]")
                       discount; // node.parent.parent.discount: the product discount

        // finally, project into an easy-to-filter form:
        return { id: item.brand_id, discount: discount };
      }
    ),
    discountOfItem983;

discountOfItem983 = itemsAndDiscounts.
  filter
  (
    function(mapped) {
      return mapped.id === "983";
    }
  )
  [0].discount;

console.log("All items and discounts: " + JSON.stringify(itemsAndDiscounts, null, 2));

console.log("Discount of #983: " + discountOfItem983);

gives:

All items and discounts: [
  {
    "id": "984",
    "discount": "15"
  },
  {
    "id": "254",
    "discount": "15"
  },
  {
    "id": "983",
    "discount": "20"
  },
  {
    "id": "253",
    "discount": "20"
  }
]
Discount of #983: 20

Here are other examples / use cases:

JSON-to-some-markup

JSON transformations, revisited (XSLT look-alike)

(at: https://jsfiddle.net/YSharpLanguage/kj9pk8oz/10)

JSON-to-JSON

Super-lightweight JSON-to-JSON transformations

(at: https://jsfiddle.net/YSharpLanguage/ppfmmu15/10)

A JavaScript equivalent of...

XSLT 3.0 REC Section 14.4 Example: Grouping Nodes based on Common Values

(at: http://jsfiddle.net/YSharpLanguage/8bqcd0ey/1)

Cf. https://www.w3.org/TR/xslt-30/#grouping-examples

A JavaScript equivalent of...

JSONiq Use Cases Section 1.1.2. Grouping Queries for JSON

(at: https://jsfiddle.net/YSharpLanguage/hvo24hmk/3)

Cf. http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping

'Hope this helps,