Skip to content

Save an array value to jsonb type column #1432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Save an array value to jsonb type column #1432

wants to merge 1 commit into from

Conversation

lifubang
Copy link

CREATE TABLE public.jsontest (
	test jsonb NULL
)
WITH (
	OIDS=FALSE
);
pool.connect(function(errp, client, done) {
  client.query('INSERT INTO jsontest(test1) VALUES($1::jsonb);', [[{"id":1, "name":"LFB"}, {"id":2, "name":"ZHM"}]], function(e,d) {
      console.log(e);
      console.log(d);
      done();
  });
});

* It returns:
{ error: invalid input syntax for type json
    at Connection.parseE (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:546:11)
    at Connection.parseMessage (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:371:19)
    at Socket.<anonymous> (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:114:22)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)
    at TCP.onread (net.js:547:20)
  name: 'error',
  length: 174,
  severity: 'ERROR',
  code: '22P02',
  detail: 'Expected ":", but found ",".',
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: 'JSON data, line 1: {"{\\"id\\":1,\\"name\\":\\"LFB\\"}",...',
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'json.c',
  line: '1151',
  routine: 'report_parse_error' }

You can fix it by:

pool.connect(function(errp, client, done) {
  client.query('INSERT INTO jsontest(test1) VALUES($1::jsonb);', [JSON.stringify([{"id":1, "name":"LFB"}, {"id":2, "name":"ZHM"}])], function(e,d) {
      console.log(e);
      console.log(d);
      done();
  });
});

But if modify the arrayString function in utils.js, It will be more convenient.

```sql
CREATE TABLE public.jsontest (
	test jsonb NULL
)
WITH (
	OIDS=FALSE
);
```

```js
pool.connect(function(errp, client, done) {
  client.query('INSERT INTO jsontest(test1) VALUES($1::jsonb);', [[{"id":1, "name":"LFB"}, {"id":2, "name":"ZHM"}]], function(e,d) {
      console.log(e);
      console.log(d);
      done();
  });
});

* It returns:
{ error: invalid input syntax for type json
    at Connection.parseE (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:546:11)
    at Connection.parseMessage (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:371:19)
    at Socket.<anonymous> (E:\develop\nodejs\mongoOPLog\node_modules\pg\lib\connection.js:114:22)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)
    at TCP.onread (net.js:547:20)
  name: 'error',
  length: 174,
  severity: 'ERROR',
  code: '22P02',
  detail: 'Expected ":", but found ",".',
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: 'JSON data, line 1: {"{\\"id\\":1,\\"name\\":\\"LFB\\"}",...',
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'json.c',
  line: '1151',
  routine: 'report_parse_error' }
```

You can fix it by:
```js
pool.connect(function(errp, client, done) {
  client.query('INSERT INTO jsontest(test1) VALUES($1::jsonb);', [JSON.stringify([{"id":1, "name":"LFB"}, {"id":2, "name":"ZHM"}])], function(e,d) {
      console.log(e);
      console.log(d);
      done();
  });
});
```

But if modify the arrayString function in utils.js, It will be more convenient.
@sehrope
Copy link
Contributor

sehrope commented Aug 29, 2017

If I'm understanding this PR correctly, you'd checking to see if the array has non-scalar children to determine that the user's intent was to treat it as JSON (as opposed to an array):

if (val && val.length > 0 && typeof(val[0]) === 'object' && typeof val[0].toPostgres != 'function') {
  return JSON.stringify(val);
} else {
  // old logic for handling arrays goes here
}

I don't think this is a good idea as it doesn't handle every situation. None of the following would be covered because the first element of the array is not an object:

[null]
[null, 1, 2, 3]
[null, {foo: 'bar'}]
[1, {foo: 'bar'}]
[false, {foo: 'bar'}]

Each of those can be serialized to valid JSON but wouldn't pass the initial check in the PR. To use a value like that you'd still have to manually serialize it to JSON prior to use.

We could check all values to see if they're all non-scalars but then you'd still have divergent behavior if an empty array is specified. Should [] be sent as an empty Postgres array, {}, or an empty JSON array, []?

Arrays have been a part of Postgres long before JSON, I think it's fair for them to have priority here. If someone is saving a JSON array (or an arbitrary JSON value which could be a string, number, or null), then they need to explicitly handle it.

@abenhamdine
Copy link
Contributor

abenhamdine commented Aug 29, 2017

I agree with @sehrope , I don't see any obvious way to distinguish arrays/json objects.
And you could also want to save a normal array in a jsonb column so it seems difficult to automatically apply the right format.
Personnaly, I indeed stringify specifically the object before passing it to the query.

Otherwise, it's better to open an issue when you think you enconter a bug : not everyone watchs the pull requests, so opening a bug allows users to easily find it & provide feedback if they want, thx !

@charmander
Copy link
Collaborator

As was said, this approach isn’t reliable. JSON.stringify is a workable workaround. See also #442.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants