代码之家  ›  专栏  ›  技术社区  ›  sam

如何在存储为字符串的bigquery字段中取消多个数组?

  •  0
  • sam  · 技术社区  · 7 年前

    我需要帮助来取消一个具有多个数组和嵌套对象中重复相同字段的字段(数量在嵌套对象的外部和内部重复)。

    数据集中有两个字段:order_id和cart,其中cart是一个字典对象,具有多个列表,其中包含列表“items”中的列表,但cart的数据类型为string。我希望每个产品和类别的输出是单独的行。

    部分工作查询的示例数据。

    #standardSQL
    WITH t AS (
        SELECT "order1234" as order_id, '{ "_id" : "cart1234" , "taxRate" : 0.0 , "items" : [{ "quantity" : 1 , "product" : { "_id" : "prod1" , "categoryIds" : [ "cat1", "cat2", "cat3"] , "name" : "Product 1" , "pricing" : { "listPrice" : { "value" : 899} , "salePrice" : { "value" : 725}}, "imagedata" : { "imageLink" : { "_id" : "img1" , "createdOn" : { "$date" : "2019-01-19T19:55:19.782Z"} , "revision" : 1} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var1" , "sku" : { "value" : "sku1" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}] , "Shipping" : true}} , { "quantity" : 2 , "product" : { "_id" : "prod2" , "categoryIds" : [ "cat2", "cat4"] , "name" : "Product 2" , "pricing" : { "listPrice" : { "value" : 199} , "salePrice" : { "value" : 150}}, "imagedata" : { "imageLink" : { "_id" : "img2" , "createdOn" : { "$date" : "2019-01-19T19:58:11.484Z"} ,  "revision" : 1} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var2" , "sku" : { "value" : "sku2" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}] , "Shipping" : true}} , { "quantity" : 3 , "product" : { "_id" : "prod3" , "categoryIds" : [ "cat2","cat4","cat5"] , "name" : "Product 3" , "pricing" : { "listPrice" : { "value" : 499} , "salePrice" : { "value" : 325}}, "imagedata" : { "imageLink" : { "_id" : "img3" , "createdOn" : { "$date" : "2019-01-15T05:34:17.556Z"} , "revision" : 3} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var3" , "sku" : { "value" : "sku3" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}], "Shipping" : true }}]}' as cart
    )
    select order_id, quantity, product, JSON_EXTRACT_SCALAR(product,'$._id') as product_id, REPLACE(category_id, '"', '') category_id, 
    JSON_EXTRACT_SCALAR(product,'$.pricing.listPrice.value') as product_list_price,
    JSON_EXTRACT_SCALAR(product,'$.pricing.salePrice.value') as product_sale_price
    from t,
    UNNEST(REGEXP_EXTRACT_ALL(cart, r'"categoryIds" : \[(.+?)]')) categoryIds WITH OFFSET pos1,
    UNNEST(SPLIT(categoryIds)) category_id,
    UNNEST(REGEXP_EXTRACT_ALL(cart, r'"product" : (.*?)\}')) product WITH OFFSET pos2,
    UNNEST(REGEXP_EXTRACT_ALL(cart, r'"quantity" : (.+?)')) quantity WITH OFFSET pos3
    where pos1= pos2 and pos1 = pos3
    

    在上面的查询中,“数量”字段不正确,并且没有显示“产品清单价格”和“产品销售价格”。记住嵌套元素中重复的数量。我认为我的regex是错误的,不知何故,我需要在每个“项目”中选择第一个“数量”,而且对于价格而言,我的regex产品并没有给我完整的产品字典,这就是为什么它们返回为空的原因。如果知道产品密钥中可能有多个符号,那么获得产品密钥完整值的正确regex是什么?

    预期结果

    order_id  quantity  product_id  category_id  product_list_price   product_sale_price
    order1234    1     prod1        cat1             899                 799
    order1234    1     prod1        cat2             899                 799
    order1234    1     prod1        cat3             899                 799
    order1234    2     prod2        cat2             199                 150
    order1234    2     prod2        cat4             199                 150
    order1234    3     prod3        cat2             499                 399 
    order1234    3     prod3        cat4             499                 399
    order1234    3     prod3        cat5             499                 399
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Mikhail Berlyant    7 年前

    如果知道产品密钥中可能有多个符号,那么获得产品密钥完整值的正确regex是什么?

    理想情况下,应该使用JSON提取(而不是REGExp提取——它会使事情复杂化)。但不幸的是,bigquery的json-extract有一些限制,不允许处理json数组

    为了克服jsonpath的bigquery“限制”,可以使用 custom function 如下示例所示:
    它使用jsonpath-0.8.0.js,可以从 https://code.google.com/archive/p/jsonpath/downloads 并上传到google cloud storage-gs://your\bucket/jsonpath-0.8.0.js

    #standardSQL
    CREATE TEMPORARY FUNCTION CUSTOM_JSON_EXTRACT(json STRING, json_path STRING)
    RETURNS ARRAY<STRING>
    LANGUAGE js AS """
            return jsonPath(JSON.parse(json), json_path);
    """
    OPTIONS (
        library="gs://your_bucket/jsonpath-0.8.0.js"
    );
    SELECT order_id, quantity, product_id, category_id
    FROM `project.dataset.table`,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].quantity')) quantity WITH OFFSET pos1,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].product._id')) product_id WITH OFFSET pos2,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].product.categoryIds')) category_ids WITH OFFSET pos3,
    UNNEST(SPLIT(category_ids)) category_id
    WHERE pos1 = pos2 AND pos1 = pos3
    

    您可以使用您提供的示例数据测试、播放上述内容:

    #standardSQL
    CREATE TEMPORARY FUNCTION CUSTOM_JSON_EXTRACT(json STRING, json_path STRING)
    RETURNS ARRAY<STRING>
    LANGUAGE js AS """
            return jsonPath(JSON.parse(json), json_path);
    """
    OPTIONS (
        library="gs://your_bucket/jsonpath-0.8.0.js"
    );
    WITH t AS (
        SELECT "order1234" AS order_id, '''{ "_id" : "cart1234" , "taxRate" : 0.0 , "items" : [
          { "quantity" : 1 , "product" : { "_id" : "prod1" , "categoryIds" : [ "cat1", "cat2", "cat3"] , "name" : "Product 1" , "imagedata" : { "imageLink" : { "_id" : "img1" , "createdOn" : { "$date" : "2019-01-19T19:55:19.782Z"} , "revision" : 1} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var1" , "sku" : { "value" : "sku1" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}] , "Shipping" : true}} , 
          { "quantity" : 2 , "product" : { "_id" : "prod2" , "categoryIds" : [ "cat2", "cat4"] , "name" : "Product 2" , "imagedata" : { "imageLink" : { "_id" : "img2" , "createdOn" : { "$date" : "2019-01-19T19:58:11.484Z"} ,  "revision" : 1} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var2" , "sku" : { "value" : "sku2" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}] , "Shipping" : true}} , 
          { "quantity" : 3 , "product" : { "_id" : "prod3" , "categoryIds" : [ "cat2","cat4","cat5"] , "name" : "Product 3" , "imagedata" : { "imageLink" : { "_id" : "img3" , "createdOn" : { "$date" : "2019-01-15T05:34:17.556Z"} , "revision" : 3} , "title" : "" , "description" : "" , "altText" : ""} , "variants" : [ ] , "productVariants" : [ { "_id" : "var3" , "sku" : { "value" : "sku3" , "modifier" : 0} , "variants" : [ ] , "quantity" : 0 , "imageLinkIds" : [ ] , "skuImageLinkIds" : [ ] , "fulfillmentData" : { "sourceName" :  null  , "sourceId" :  null  , "sourceSku" :  null  , "sourceMethod" :  null  , "sourceRedirectUrl" :  null  , "sourceRedirectAppKey" :  null }}], "Shipping" : true }}
        ]}''' AS cart    
    )
    SELECT order_id, quantity, product_id, category_id
    FROM t,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].quantity')) quantity WITH OFFSET pos1,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].product._id')) product_id WITH OFFSET pos2,
    UNNEST(CUSTOM_JSON_EXTRACT(cart, '$.items[*].product.categoryIds')) category_ids WITH OFFSET pos3,
    UNNEST(SPLIT(category_ids)) category_id
    WHERE pos1 = pos2 AND pos1 = pos3
    

    以结果

    Row order_id    quantity    product_id  category_id  
    1   order1234   1           prod1       cat1     
    2   order1234   1           prod1       cat2     
    3   order1234   1           prod1       cat3     
    4   order1234   2           prod2       cat2     
    5   order1234   2           prod2       cat4     
    6   order1234   3           prod3       cat2     
    7   order1234   3           prod3       cat4     
    8   order1234   3           prod3       cat5     
    

    注: product_list_price product_sale_price 不存在于您的样本DAAT中,因此不在上述结果中。但现在的查询非常干净和简单,所以希望您能够轻松地添加这些内容。