Skip to content

Cloud Spanner Query Works in the Webinterface but not with the node.js client. #2012

Description

@aronsuarez

Hi

I have the following query that i run with the node.js client:

let query = {
    sql:`SELECT id, name, ARRAY(SELECT AS STRUCT name, id FROM files WHERE files.id in UNNEST(articles.files)) AS files FROM articles WHERE lang = @lang AND id = @id`,
    params:{
      lang: req.swagger.params.lang.value,
      id: req.swagger.params.id.value
    }
  };

When i run the query in the spanner web interface it works fine, i get this back:
049db33b-57f9-45bf-83a4-5eeb6f5b0329 amet ut [["Lorem sunt","54841749-5243-4ce5-b84e-84d7b5ba1e2a"]]

this is the name, the id, and the struct array that i have created in the query with one entry in this case.
Now when i run the query with the node client i get this data:

[
   {
     "id": "049db33b-57f9-45bf-83a4-5eeb6f5b0329",
     "name": "amet ut",
     "files": [
       {}
     ]
   }
 ]

The query works expected, the number of object in the files array is correct also with other entries. But the node.js client give me only empty objects back in the array, but when i change the query to this:

let query = {
    sql:`SELECT id, name, ARRAY(SELECT id FROM files WHERE files.id in UNNEST(articles.files)) AS files FROM articles WHERE lang = @lang AND id = @id`,
    params:{
      lang: req.swagger.params.lang.value,
      id: req.swagger.params.id.value
    }
  };

i got this back:

[
   {
     "id": "049db33b-57f9-45bf-83a4-5eeb6f5b0329",
     "name": "amet ut",
     "files": [
       "da2c165e-f7ef-11e6-bc64-92361f002671"
     ]
   }
 ]

I think this is a problem with the node.js client, whe it try to map the struct to a json array.

System:
OS: macOS 10.12.3 / ubuntu 16.04
node: 6.9.1
google-cloud: 0.47.0

Thanks for help

Activity

  1. stephenplusplus commented on Feb 21, 2017

    @stephenplusplus
    Contributor

    Thanks for reporting, @nor-bu.

    @vkedia is it possible to write up a test case for this, to make sure our data handling is correct?

  2. added
    api: spannerIssues related to the Spanner API.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    on Feb 21, 2017
  3. vkedia commented on Feb 21, 2017

    @vkedia
    Contributor

    @stephenplusplus I think something like this should work:
    select 1 as id, ARRAY(select as struct 2 as id, "hello" as name)

  4. vkedia commented on Feb 21, 2017

    @vkedia
    Contributor

    I tried this query by modifying the quickstart but got an error:

    $ node quickstart.js 
    github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:39
      this.value = value.toString();
                        ^
    
    TypeError: Cannot read property 'toString' of undefined
        at new Int (github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:39:21)
        at decodeValue_ (github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:71:19)
        at github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:98:20
        at Array.forEach (native)
        at decodeValue_ (github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:95:16)
        at github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:85:18
        at Array.map (native)
        at decodeValue_ (github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:84:27)
        at Object.decode (github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/codec.js:124:10)
        at github-repos/nodejs-docs-samples/spanner/node_modules/@google-cloud/spanner/src/partial-result-stream.js:184:20
    
  5. stephenplusplus commented on Feb 21, 2017

    @stephenplusplus
    Contributor

    Looking into it now.

  6. stephenplusplus commented on Feb 21, 2017

    @stephenplusplus
    Contributor

    I just released a fix for this in @google-cloud/[email protected]. Would you mind trying the new version?

  7. vkedia commented on Feb 21, 2017

    @vkedia
    Contributor

    It seems to be better than before but I dont think its complete fixed. I am trying this

    const query = {
      sql: 'select 1 as id, ARRAY(select as struct 2 as id2, "hello" as name) as f2'
      //sql: 'SELECT 1 as id'
    };
    
    // Execute a simple SQL statement
    database.run(query)
      .then((results) => {
        const rows = results[0];
    
        rows.forEach((row) => console.log(row.toJSON()["f2"]));
      });
    

    Output is:

    [ [ { name: 'id2', value: [Object] },
        { name: 'name', value: 'hello' } ] ]
    

    Why is it an array inside an array. It should just be array of objects.
    Also for id2 why is the value [Object]? It should just be a spanner.Int

  8. reopened this on Feb 21, 2017
  9. stephenplusplus commented on Feb 21, 2017

    @stephenplusplus
    Contributor

    Why is it an array inside an array. It should just be array of objects.

    This is the (simplified) raw response:

    SELECT 1 as id, ARRAY(select as struct 2 as id, "hello" as name)

    {
      "metadata": {
        "rowType": {
          "fields": [
            {
              "name": "id",
              "type": {
                "code": "INT64"
              }
            },
            {
              "name": "",
              "type": {
                "code": "ARRAY",
                "arrayElementType": {
                  "code": "STRUCT",
                  "structType": {
                    "fields": [
                      {
                        "name": "id",
                        "type": {
                          "code": "INT64"
                        }
                      },
                      {
                        "name": "name",
                        "type": {
                          "code": "STRING"
                        }
                      }
                    ]
                  }
                }
              }
            }
          ]
        }
      },
      "values": [
        {
          "stringValue": "1"
        },
        {
          "listValue": {
            "values": [
              {
                "listValue": {
                  "values": [
                    {
                      "stringValue": "2"
                    },
                    {
                      "stringValue": "hello"
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }

    It looks like it's saying it's returning an array of structs. And structs are represented as arrays in our library. So, we end up with an array of arrays.

    Also for id2 why is the value [Object]? It should just be a spanner.Int

    console.log only prints a certain amount of levels deep. You can use console.log(JSON.stringify(object, null, 2)) to get a better readout:

    [
      {
        "id2": {
          "value": "2"
        },
        "name": "hello"
      }
    ]
  10. stephenplusplus commented on Feb 21, 2017

    @stephenplusplus
    Contributor

    I think everything is okay here, so I'm going to re-close, but re-open again if something is not working properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

api: spannerIssues related to the Spanner API.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions