Bind Parent/sibling properties in JQ to use in dynamic conditionals

梦想的初衷 提交于 2020-02-25 10:13:56

问题


I want to create a JQ function that allows me to to filter an array in the JSON tree, based on parent's / sibling properties;

1 - I want to wrap function but i can't due to the scope of parent; 2 - I want to invoke that function but with other properties;

Some dummy Data:

[
 {
        "storeId": "s2",
        "storehouseInfo": {
            "id": "025453",
            "name": "00211 NW, OR",
            "maxPallets": 10
        },
        "workorder":{
            "id": "w2s2",
            "startDate": "2019-09-06T10:00:00.000Z",
            "vendorId":"v2"
        },
        "events": [    
            {
                "id": "e4",
                "storeId": "s2",
                "vendorId": "v1",
                "startDate": "2019-09-05T10:00:00.000Z",
                "endDate": "2019-09-14T00:00:00.000Z",
                "palletsUsed": 5
            },
            {
                "id": "e5",
                "storeId": "s2",
                "vendorId": "v2",
                "startDate": "2019-09-05T00:00:00.000Z",
                "endDate": "2019-09-14T00:00:00.000Z",
                "palletsUsed": 5
            },
            {
                "id": "e10",
                "storeId": "s2",
                "vendorId": "v1",
                "startDate": "2019-09-06T10:00:00.000Z",
                "endDate": "2019-09-14T00:00:00.000Z",
                "palletsUsed": 5
            },
            {
                "id": "e11",
                "storeId": "s2",
                "vendorId": "v2",
                "startDate": "2019-09-06T00:00:00.000Z",
                "endDate": "2019-09-14T00:00:00.000Z",
                "palletsUsed": 5
            },
            {
                "id": "e12",
                "storeId": "s2",
                "vendorId": "v2",
                "startDate": "2019-09-06T10:00:00.000Z",
                "endDate": "2019-09-14T00:00:00.000Z",
                "palletsUsed": 5
            }
        ]
    },
]

Current working function:

. | map( . as $parent | 
         .
         + 
         {
            "conflictsInPeriod":
             [.events[] | (
                 getFieldsThatCheckConditionInArray(
                 # conditions
                 ( 
                    ( ($parent.workorder.startDate | dateDaysAgo(12*7) ) < .endDate)
                                and
                    (.vendorId == $parent.workorder.vendorId)
                  );
                  # props  we want to return
                 {
                     event:.id,
                     wo_sd: $parent.workorder.startDate[:10],
                     workorder_id: $parent.workorder.id
                 })   
             )]
          }
       )    

Some aux functions:

def generateConflictArray(arrayName;arrayToCheck;conflictToCheck):
        map( . +
                {
                    (arrayName): [arrayToCheck | (conflictToCheck)]
                }
        );

def getFieldsThatCheckConditionInArray(condition;returnValues) :
        if (condition) then (returnValues) else empty end; 

Desired Function CALL:

 . | generateConflictArray(
        "conflictsInPeriod";
        .events[];
        getFieldsThatCheckConditionInArray(
          # conditions
          ( 
                ( ($parent.workorder.startDate | dateDaysAgo(12*7) ) < .endDate)
                                and
                   (.vendorId == $parent.workorder.vendorId)
          );
           # props we want to return
           {
               event:.id,
               event_endDate:.endDate,
               wo_sd: $parent.workorder.startDate[:10],
               workorder_id: $parent.workorder.id
           })   
        )

Desired Output (All the array data, + newly created array " "conflictsInPeriod"", inside each element of the array):

[
{
 "conflictsInPeriod":[
      {
        "event": "e5",
        "workorder_sd": "2019-09-06",
        "workorder_id": "w2s2"
      },
      {
        "event_id": "e11",
        "workorder_sd": "2019-09-06",
        "workorder_id": "w2s2"
      },
      {
        "event_id": "e12",
        "workorder_sd": "2019-09-06",
        "workorder_id": "w2s2"
      }
]
}
]
...

回答1:


Maybe this is closer to what you're looking for:

def etl(keyname; arrayname; cond; result):
  def etl:
    . as $parent
    | .[arrayname][]
    | { parent: $parent, child: .}
    | select(cond) | result;

  {(keyname): map(etl)}
 ;

## Invocation:
etl("conflictsInPeriod";
    "events";
    ( (.parent.workorder.startDate | dateDaysAgo(12*7) ) < .child.endDate)
      and
      (.child.vendorId == .parent.workorder.vendorId);
   {
     event: .child.id,
     wo_sd: .parent.workorder.startDate[:10],
     workorder_id: .parent.workorder.id
   }
)

Notice how the conditions are written in relation to .parent and .child rather than $parent and ..




回答2:


It may be that one cannot achieve in jq what you think you want, but the following comes close:

def etl( array; cond; result):
  array[]
  | if cond then result else empty end ;

{conflictsInPeriod: map(
  . as $parent
  | etl(.events;
       ( ($parent.workorder.startDate | dateDaysAgo(12*7) ) < .endDate)
       and
       (.vendorId == $parent.workorder.vendorId);
       {
         event:.id,
         wo_sd: $parent.workorder.startDate[:10],
         workorder_id: $parent.workorder.id
       }
    )
  )
}


来源:https://stackoverflow.com/questions/57558872/bind-parent-sibling-properties-in-jq-to-use-in-dynamic-conditionals

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!