GraphQL API - Exact match vs. Fuzzy match

Highlighted

Hi All,

I'm using GraphQL API to return all products that match a selected tag. However, in my testing, it appears that the result set returned is via fuzzy match instead of exact match. 

Is there a way/flag/setting to ensure that the GraphQL API uses exact match? 

I'm using Shopify's GraphiQL App. Below is my search criteria and results.

Steps to Reproduce:

  1. Create a product with a tag of "16 A"
  2. Create a product search (GraphQL API) for products tagged with "16a"

Expected Results

  • Only products tagged with "16a" are returned

Actual Results

  • Product with tag "16 A" is returned (even though it is not an exact match). 

Any help would greatly be appreciated. 

Thanks,

Mariano

 

Query & Results

 

# QUERY
query ($myTags: String) {
  products(first: 100,  query: $myTags) {
    pageInfo {
      hasNextPage
      hasPreviousPage
    }
    edges {
    
      node {
        id
        title
        tags  
      }
    }
  }
}

# VARIABLES
{
  "myTags": "tag:'16a'"
} 


# RESULTS
{
  "data": {
    "products": {
      "pageInfo": {
        "hasNextPage": false,
        "hasPreviousPage": false
      },
      "edges": [
        {
          "node": {
            "id": "gid://shopify/Product/4659242795111",
            "title": "Test - A",
            "tags": [
              "16 A"
            ]
          }
        }
      ]
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 102,
      "actualQueryCost": 3,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 997,
        "restoreRate": 50
      }
    }
  }
}

 

 

search.png

0 Likes
Highlighted
Shopify Partner
528 38 109

Well this certainly has all the merits of a "gotcha" doesn't it? You'd think that some regex-type variables in the query would force this. Apparently not!

0 Likes
Highlighted
Shopify Staff
Shopify Staff
55 6 8

Hi @3Revolutions,

We're unable to replicate at the moment. Can you provide a X-Request-Id from the response headers so we can dig deeper?

Screen Shot 2020-07-29 at 6.32.11 PM.png

Callum | Developer Support @ Shopify
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Click Accept as Solution 

0 Likes
Highlighted

Hi @CalD ,

Thanks for looking into this...

You are right. That specific query "16a" is working correctly. Sorry about that. However, if you search for "16", you should see results returned that are not exact matches. 

Here are the X response headers:

x-content-type-options: nosniff
x-dc:gke
x-download-options:noopen
x-permitted-cross-domain-policies: none
x-request-id: 7dc36b2859d4f6a89a6a0c388db0bb0c
x-runtime: 0.283748
x-upstream-request-id: 8e462827-c134-46d5-85e7-bc8f182af7a6
x-xss-protection: 1; mode=block

 

16.png

 

{
  "data": {
    "products": {
      "pageInfo": {
        "hasNextPage": false,
        "hasPreviousPage": false
      },
      "edges": [
        {
          "node": {
            "id": "gid://shopify/Product/4659242795111",
            "title": "Test - A",
            "tags": [
              "16 A"
            ]
          }
        },
        {
          "node": {
            "id": "gid://shopify/Product/4659244728423",
            "title": "Test",
            "tags": [
              "16"
            ]
          }
        },
        {
          "node": {
            "id": "gid://shopify/Product/4659911393383",
            "title": "Test - A2",
            "tags": [
              "16 Apples"
            ]
          }
        },
        {
          "node": {
            "id": "gid://shopify/Product/4659911491687",
            "title": "Test - A3",
            "tags": [
              "16 Alligators"
            ]
          }
        }
      ]
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 102,
      "actualQueryCost": 6,
      "throttleStatus": {
        "maximumAvailable": 1000,
        "currentlyAvailable": 994,
        "restoreRate": 50
      }
    }
  }
}

 

0 Likes
Highlighted
Shopify Staff
Shopify Staff
55 6 8

The partial match results you're getting are expected behaviour, according to the search syntax here.

* equality depends on how a field is indexed. For numeric fields : represents equality. For tokenized fields, equality exists if the term is found anywhere in the field

The tags field on a product is tokenized, so '16' would return '16 A' etc. Two options for you are either to perform some sort of additional filtering on your end once the results are returned, to only select the ones that match your query exactly, or you can use more specific tags on your products to prevent unwanted overlap?

Callum | Developer Support @ Shopify
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Click Accept as Solution 

0 Likes
Highlighted
Shopify Partner
528 38 109

What's strange is I was responding to another post regarding searching for orders by tags. While the REST API was giving the OP some issues, I pointed them to the GraphQL API. The strange part is I provided a test example. Searching for an order that had the tag test_tag defined. There was a single record passed back. But when I searched for just test for the tag query no results came up. Doesn't this contradict what is discussed above? Or perhaps it has to do with the matched tag not having a space in it? 

Here are the API request/response pairs below. Just curious...

 

POST https://{my_shop}.myshopify.com/admin/api/2020-04/graphql.json HTTP/1.1
X-Shopify-Access-Token: {my_token}
Content-Type: application/graphql
User-Agent: PostmanRuntime/7.26.2
Accept: */*
Postman-Token: 6e2f9e4e-b250-4ef2-a598-f598b75cc5be
Host: {my_shop}.myshopify.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 159
Cookie: __cfduid=d63090a1de3eaa36b02875cfabcf0fc221595426473

query {
  orders(first: 10, query:"tag:test") {
    edges {
      cursor
      	node {
        	id
          name
          tags
      }
    }
  }
}
HTTP/1.1 200 OK
Date: Fri, 31 Jul 2020 13:09:14 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-Sorting-Hat-PodId: 161
X-Sorting-Hat-ShopId: 3036253
Vary: Accept-Encoding
Referrer-Policy: origin-when-cross-origin
X-Frame-Options: DENY
X-ShopId: 3036253
X-ShardId: 161
X-Stats-UserId: 
X-Stats-ApiClientId: 309925
X-Stats-ApiPermissionId: 8304915
X-Shopify-API-Terms: By accessing or using the Shopify API you agree to the Shopify API License and Terms of Use at https://www.shopify.com/legal/api-terms
X-Shopify-API-Version: 2020-04
Content-Language: en
Strict-Transport-Security: max-age=7889238
X-Request-Id: d1ae6d3c-adf8-44a3-9c5f-9eed85baf6fb
X-Shopify-Stage: production
Content-Security-Policy: default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' https://* shopify-pos://*; block-all-mixed-content; child-src 'self' https://* shopify-pos://*; connect-src 'self' wss://* https://*; frame-ancestors 'none'; img-src 'self' data: blob: https:; script-src https://cdn.shopify.com https://cdn.shopifycdn.net https://checkout.us.shopifycs.com https://js-agent.newrelic.com https://bam.nr-data.net https://api.stripe.com https://mpsnare.iesnare.com https://appcenter.intuit.com https://www.paypal.com https://js.braintreegateway.com https://c.paypal.com https://maps.googleapis.com https://www.google-analytics.com https://v.shopify.com https://widget.intercom.io https://js.intercomcdn.com 'self' 'unsafe-inline' 'unsafe-eval'; upgrade-insecure-requests; report-uri /csp-report?source%5Baction%5D=query&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fgraphql&source%5Bsection%5D=admin_api&source%5Buuid%5D=d1ae6d3c-adf8-44a3-9c5f-9eed85baf6fb
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
X-XSS-Protection: 1; mode=block; report=/xss-report?source%5Baction%5D=query&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fgraphql&source%5Bsection%5D=admin_api&source%5Buuid%5D=d1ae6d3c-adf8-44a3-9c5f-9eed85baf6fb
X-Dc: gcp-us-central1,gcp-us-central1
NEL: {"report_to":"network-errors","max_age":2592000,"failure_fraction":0.01,"success_fraction":0.0001}
Report-To: {"group":"network-errors","max_age":2592000,"endpoints":[{"url":"https://monorail-edge.shopifycloud.com/v1/reports/nel/20190325/shopify"}]}
CF-Cache-Status: DYNAMIC
cf-request-id: 044696c2a6000083c9880fa200000001
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5bb78d7ddd0683c9-ORD
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
Content-Length: 189

{"data":{"orders":{"edges":[]}},"extensions":{"cost":{"requestedQueryCost":12,"actualQueryCost":2,"throttleStatus":{"maximumAvailable":1000.0,"currentlyAvailable":998,"restoreRate":50.0}}}}

------------------------------------------------------------------

POST https://{my_shop}.myshopify.com/admin/api/2020-04/graphql.json HTTP/1.1
X-Shopify-Access-Token: {my_token}
Content-Type: application/graphql
User-Agent: PostmanRuntime/7.26.2
Accept: */*
Postman-Token: 16575bd1-5765-43fd-a31a-7d66c682751e
Host: {my_shop}.myshopify.com
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 163
Cookie: __cfduid=d63090a1de3eaa36b02875cfabcf0fc221595426473

query {
  orders(first: 10, query:"tag:test_tag") {
    edges {
      cursor
      	node {
        	id
          name
          tags
      }
    }
  }
}
HTTP/1.1 200 OK
Date: Fri, 31 Jul 2020 13:09:24 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-Sorting-Hat-PodId: 161
X-Sorting-Hat-ShopId: 3036253
Vary: Accept-Encoding
Referrer-Policy: origin-when-cross-origin
X-Frame-Options: DENY
X-ShopId: 3036253
X-ShardId: 161
X-Stats-UserId: 
X-Stats-ApiClientId: 309925
X-Stats-ApiPermissionId: 8304915
X-Shopify-API-Terms: By accessing or using the Shopify API you agree to the Shopify API License and Terms of Use at https://www.shopify.com/legal/api-terms
X-Shopify-API-Version: 2020-04
Content-Language: en
Strict-Transport-Security: max-age=7889238
X-Request-Id: 23e9d339-1e16-48f9-9822-389b0abb98a3
X-Shopify-Stage: production
Content-Security-Policy: default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' https://* shopify-pos://*; block-all-mixed-content; child-src 'self' https://* shopify-pos://*; connect-src 'self' wss://* https://*; frame-ancestors 'none'; img-src 'self' data: blob: https:; script-src https://cdn.shopify.com https://cdn.shopifycdn.net https://checkout.us.shopifycs.com https://js-agent.newrelic.com https://bam.nr-data.net https://api.stripe.com https://mpsnare.iesnare.com https://appcenter.intuit.com https://www.paypal.com https://js.braintreegateway.com https://c.paypal.com https://maps.googleapis.com https://www.google-analytics.com https://v.shopify.com https://widget.intercom.io https://js.intercomcdn.com 'self' 'unsafe-inline' 'unsafe-eval'; upgrade-insecure-requests; report-uri /csp-report?source%5Baction%5D=query&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fgraphql&source%5Bsection%5D=admin_api&source%5Buuid%5D=23e9d339-1e16-48f9-9822-389b0abb98a3
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
X-XSS-Protection: 1; mode=block; report=/xss-report?source%5Baction%5D=query&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fgraphql&source%5Bsection%5D=admin_api&source%5Buuid%5D=23e9d339-1e16-48f9-9822-389b0abb98a3
X-Dc: gcp-us-central1,gcp-us-central1
NEL: {"report_to":"network-errors","max_age":2592000,"failure_fraction":0.01,"success_fraction":0.0001}
Report-To: {"group":"network-errors","max_age":2592000,"endpoints":[{"url":"https://monorail-edge.shopifycloud.com/v1/reports/nel/20190325/shopify"}]}
CF-Cache-Status: DYNAMIC
cf-request-id: 044696e9c5000003a63306a200000001
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5bb78dbc6ee003a6-ORD
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
Content-Length: 363

{"data":{"orders":{"edges":[{"cursor":"eyJsYXN0X2lkIjoyNTY3NDQwMjM2NzA2LCJsYXN0X3ZhbHVlIjoxNTk0MjI4NjI4MDAwfQ==","node":{"id":"gid:\/\/shopify\/Order\/2567440236706","name":"#1316","tags":["test_tag"]}}]}},"extensions":{"cost":{"requestedQueryCost":12,"actualQueryCost":3,"throttleStatus":{"maximumAvailable":1000.0,"currentlyAvailable":997,"restoreRate":50.0}}}}

------------------------------------------------------------------

 

0 Likes