JSONata grouping in new objects

88 Views Asked by At

I'm looking for a solution of grouping elements from a flat hierarchy into a encapsulated one with the help of JSONata.

Given that I have the following input data:

[  
  {
    "restaurantName": "Pizza Place",
    "restaurantId": "1",
    "dishName": "Margherita  Pizza",
    "dishId": "A"
  },
  {
    "restaurantName": "Pizza Place",
    "restaurantId": "1",
    "dishName": "Four Cheese Pizza",
    "dishId": "B"
  },
  {
    "restaurantName": "Pizza Palace",
    "restaurantId": "2",
    "dishName": "Margherita  Pizza",
    "dishId": "A"
  },
  {
    "restaurantName": "Pizza Palace",
    "restaurantId": "2",
    "dishName": "Four Cheese Pizza",
    "dishId": "B"
  },
  {
    "restaurantName": "Pizza Palace",
    "restaurantId": "2",
    "dishName": "Pepperoni Pizza",
    "dishId": "C"
  }
]

I want to group them together by restaurants like so:

[
  {
    "restaurantName": "Pizza Place",
    "restaurantId": "1",
    "menu": [
      {
        "dishName": "Margherita  Pizza",
        "dishId": "A"
      },
      {
        "dishName": "Four Cheese Pizza",
        "dishId": "B"
      }
    ]
  },
  {
    "restaurantName": "Pizza Palace",
    "restaurantId": "2",
    "menu": [
      {
        "dishName": "Margherita  Pizza",
        "dishId": "A"
      },
      {
        "dishName": "Four Cheese Pizza",
        "dishId": "B"
      },
      {
        "dishName": "Pepperoni Pizza",
        "dishId": "C"
      }
    ]
  }
]

I already tried to find a solution with the help of the JSONata Exerciser and this solution seems to work on the reduced input data set but as soon as I use the full data set (just more restaurants and more dishes) I can a time out exception (maybe due to infinite loops):

$distinct(
        $map($distinct($), function($v0, $i, $a) {
        {
            "restaurantName":$v0.restaurantName,
            "restaurantId": $v0.restaurantId,
            "menu":$distinct($filter($$, function($v1,$i,$a) {$v1.restaurantId = $v0.restaurantId}).{
                "dishName": dishName,
                "dishId": dishId
            })
        }
    })
)

If anyone has a solution and an explanation on how to best achieve this with JSONata this would be of great help.

Greetings

2

There are 2 best solutions below

5
On BEST ANSWER

You can group by restaurantId into an object, and then iterate over object entries using the $each function:

$${
  restaurantId: $
} ~> $each(function($objects, $id) {{
  "restaurantId": $id,
  "restaurantName": $objects[0].restaurantName,
  "menu": $objects.{
    "dishName": dishName,
    "dishId": dishId
  }
}})

Check it out on the Stedi Playground: https://stedi.link/qJhXW0h

0
On

This seems to work and I feel is a little more intuitive to follow:

${
    (restaurantName & restaurantId): {
        "restaurantName": $[0].restaurantName,
        "restaurantId": $[0].restaurantId,
        "menu": $.$sift(function($_, $k){$k~>/^dish/})
    }
}.*

Grouping by restaurantName and restaurantId, we map the name and id for each group and pick out the dish* properties to build out the menu. Then map to the values of the grouping.