bazaarvoice / jolt

JSON to JSON transformation library written in Java.
Apache License 2.0
1.55k stars 329 forks source link

Skipping index value with null objects #316

Closed bulletblp4 closed 5 years ago

bulletblp4 commented 7 years ago

I am trying convert a multiple level lists to a list of list. The input object domesticAnimals has either the dog list populate or the cat list. I want to combine all dog type across all the domesticAnimals array in one list and similarly for cats. Since I am referencing to the domesticAnimal index it populates the pets[].dog[] with 0th and 1st element as null. Is there an operator that would skip the null object, or is there any better way to handle this.

{
  "sanctuary": [
    {
      "animals": [
        {
          "domesticAnimals": [
            {
              "id": "001",
              "dogs": [],
              "cats": [
                {
                  "name": "qwe"
                }
              ]
            },
            {
              "id": "002",
              "promotions": [],
              "cats": [
                {
                  "name": "qwe"
                }
              ]
            },
            {
              "id": "003",
              "dogs": [
                {
                  "name": "bla1",
                  "food": "dsfds"
                }
              ],
              "products": [],
              "ads": []
            },
            {
              "id": "004",
              "dogs": [
                {
                  "name": "bla2",
                  "food": "dsfds"
                }
              ],
              "cats": []
            }
          ]
        }
      ]
    }
  ]
}

spec

[
  {
    "operation": "shift",
    "spec": {
      "sanctuary": {
        "*": {
          "animals": {
            "*": {
              "domesticAnimals": {
                "*": {
                  "cats": {
                    "*": {
                      "@(2,id)": "pets[&5].cats[&3].id",
                      "name": "pets[&5].cats[&3].name"
                    }
                  },
                  "dogs": {
                    "*": {
                      "@(2,id)": "pets[&5].dogs[&3].id",
                      "name": "pets[&5].dogs[&3].name",
                      "food": "pets[&5].dogs[&3].food"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
 }
]

output

{
  "pets" : [ {
    "cats" : [ {
      "id" : "001",
      "name" : "qwe"
    }, {
      "id" : "002",
      "name" : "qwe"
    } ],
    "dogs" : [ null, null, {
      "food" : "dsfds",
      "id" : "003",
      "name" : "bla1"
    }, {
      "food" : "dsfds",
      "id" : "004",
      "name" : "bla2"
    } ]
  } ]
}

expected output

{
  "pets" : [ {
    "cats" : [ {
      "id" : "001",
      "name" : "qwe"
    }, {
      "id" : "002",
      "name" : "qwe"
    } ],
    "dogs" : [  {
      "food" : "dsfds",
      "id" : "003",
      "name" : "bla1"
    }, {
      "food" : "dsfds",
      "id" : "004",
      "name" : "bla2"
    } ]
  } ]
}
milosimpson commented 7 years ago

You have to do two shift operations.

First one, is used to push the "id" field "down", maintaining the same "structure" of the input "domesticAnimals" and "cats" and "dogs" arrays.

The second shift, can then build the desired "cat" and "dogs" output arrays, by moving/accumulating the now "correct" "cat" and "dog" entries.

Spec

[
  {
    "operation": "shift",
    "spec": {
      "sanctuary": {
        "*": {
          "animals": {
            "*": {
              "domesticAnimals": {
                "*": {
                  "cats": {
                    "*": {
                      "name": "temp[&3].cats[&1].name",
                      "@(2,id)": "temp[&3].cats[&1].id"
                    }
                  },
                  "dogs": {
                    "*": {
                      "name": "temp[&3].dogs[&1].name",
                      "food": "temp[&3].dogs[&1].food",
                      "@(2,id)": "temp[&3].dogs[&1].id"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    },
  {
    "operation": "shift",
    "spec": {
      "temp": {
        "*": {
          "cats": {
            "*": "pets[0].cats[]"
          },
          "dogs": {
            "*": "pets[0].dogs[]"
          }
        }
      }
    }
  }
]
milosimpson commented 7 years ago

Technically this can be "simplified" to this spec, but it is harder to tell what is going on. Spec

[
  {
    "operation": "shift",
    "spec": {
      "sanctuary": {
        "*": {
          "animals": {
            "*": {
              "domesticAnimals": {
                "*": {
                  "cats|dogs": {
                    "*": {
                      "*": "temp[&3].&2[&1].&",
                      "@(2,id)": "temp[&3].&2[&1].id"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    },
  {
    "operation": "shift",
    "spec": {
      "temp": {
        "*": {
          "*": {
            "*": "pets[0].&1[]"
          }
        }
      }
    }
  }
]
bulletblp4 commented 7 years ago

Thanks for your quick response.... That worked like magic.. Had never used | operator before.