28

タイプの列を含むテーブルに対するこの単純なクエリがありますbigint

ただし、クエリを実行すると、pg-promiseはこの列の値を文字列として返します。ドキュメントでそれに関する情報を見つけることができません。それは標準的な動作ですか?

var ids = [180, 120];

db.any('SELECT id_brand, brand from catalog_brand WHERE id_brand in ($1:csv)', [ids])
    .then((data) => {
        // return results
    });

dataid を int ではなく string として、次の形式を取ります。

[{id_brand: "180", brand: "Ford"}, {id_brand: "120", brand: "Nike"}]

実際の型を返すようにpg-promiseに指示するものはありますか?

4

4 に答える 4

49

その下には、歴史的に蓄積されてきたものがたくさんあります。ただし、Node.js v10.4.0 以降を使用している場合は、これをすべてスキップしてUPDATE-2、下部のセクションにジャンプできます。


これは確かに標準的な動作です。

bigintは 64 ビットであり、すべての 64 ビット整数は基礎となるnode-postgresドライバーによって type として返されstring、32 ビット整数は として返されnumberます。

この理由は、JavaScript では 64 ビット整数が正確なネイティブ表現を持たず、特定の精度で 64 ビット数値しか表現できず、64 ビット数値の全範囲を表現するのに適していないためです。

参照: Node.js で 64 ビット整数演算を行うには?


この問題には 3 つの解決策が考えられます。最適な解決策を選択してください。

解決策 1

ID の保存に 64 ビット整数を使用しないでください。テーブルに 40 億を超えるレコードがないと予想される場合は、int代わりにデフォルトの型である 32 ビットを使用してください。自動的に整数として返されます。

解決策 2

返された ID をオンザフライで整数に変換しますが、ID が十分に高い数値 (53 ビット) に達すると、変換された値が歪んだり変更されたりすることに注意してください。

ただし、文字列を 64 ビット整数に適切に変換できる特殊なライブラリを使用することはできますが (上のリンクを参照)、複数のクエリで使用するのは面倒です。


オンザフライで ID を変換する例:

db.each('SELECT id_brand FROM catalog_brand WHERE id_brand in ($1:csv)', [ids], cat=> {
    cat.id_brand = parseInt(cat.id_brand)
})
    .then(rows => {
        // id_brand is now an integer in each row
    });

Database.eachを参照してください。

別の例として、レコード数は常に として返されるbigintため、これらを取得する最善の方法は、次のようにインライン値変換 + 変換を使用することです。

db.one('SELECT count(*) FROM catalog_brand', [], c => +c.count)
    .then(count => {
        // count = a proper integer value, rather than an object with a string
    });

Database.oneを参照してください。

解決策 3

基になるnode-postgresドライバーで変換の安全性を無視し、そのような型をあらゆる場所で整数に変換することができます。それが一般的に良いアイデアであるかどうかはわかりませんが、簡単に実行できるということだけですpgp.pg.types.setTypeParser(...)pg-typesを参照):

// Convert bigserial + bigint (both with typeId = 20) to integer:
pgp.pg.types.setTypeParser(20, parseInt);

更新-1

pg-promiseTypeScript 経由で v9 以降を使用する場合、上記のコードを次のように置き換えることができます。

pgp.pg.types.setTypeParser(TypeId.INT8, parseInt);

ソリューション 2 と 3 は同じことを行いますが、2 つの異なるレベルで行われることに注意してください。

  • ソリューション 2 の明示的なローカル変換
  • ソリューション 3 の暗黙的なグローバル変換

更新-2

ライブラリのバージョン 9.3.0では、Node.js v10.4.0 以降を実行している場合に使用できるようになったネイティブBigInt型のサポートが追加されました。

ドライバーが自動的にBigIntBIGINT+に使用するようにするにはBIGSERIAL:

pgp.pg.types.setTypeParser(20, BigInt); // Type Id 20 = BIGINT | BIGSERIAL

詳細については、プロジェクトの WiKi にある BigIntマニュアルを参照してください。

于 2016-08-27T01:40:51.040 に答える
8

@vitaly-tの答えはすべてを説明しています!

@vitaly-t answer の postgree (ソリューション 3) での暗黙的なグローバル変換の場合。

ここで知っておくべきこと:

const typesBuiltins = {
    BOOL: 16,
    BYTEA: 17,
    CHAR: 18,
    INT8: 20,
    INT2: 21,
    INT4: 23,
    REGPROC: 24,
    TEXT: 25,
    OID: 26,
    TID: 27,
    XID: 28,
    CID: 29,
    JSON: 114,
    XML: 142,
    PG_NODE_TREE: 194,
    SMGR: 210,
    PATH: 602,
    POLYGON: 604,
    CIDR: 650,
    FLOAT4: 700,
    FLOAT8: 701,
    ABSTIME: 702,
    RELTIME: 703,
    TINTERVAL: 704,
    CIRCLE: 718,
    MACADDR8: 774,
    MONEY: 790,
    MACADDR: 829,
    INET: 869,
    ACLITEM: 1033,
    BPCHAR: 1042,
    VARCHAR: 1043,
    DATE: 1082,
    TIME: 1083,
    TIMESTAMP: 1114,
    TIMESTAMPTZ: 1184,
    INTERVAL: 1186,
    TIMETZ: 1266,
    BIT: 1560,
    VARBIT: 1562,
    NUMERIC: 1700,
    REFCURSOR: 1790,
    REGPROCEDURE: 2202,
    REGOPER: 2203,
    REGOPERATOR: 2204,
    REGCLASS: 2205,
    REGTYPE: 2206,
    UUID: 2950,
    TXID_SNAPSHOT: 2970,
    PG_LSN: 3220,
    PG_NDISTINCT: 3361,
    PG_DEPENDENCIES: 3402,
    TSVECTOR: 3614,
    TSQUERY: 3615,
    GTSVECTOR: 3642,
    REGCONFIG: 3734,
    REGDICTIONARY: 3769,
    JSONB: 3802,
    REGNAMESPACE: 4089,
    REGROLE: 4096
};

ここで見つけることができます
https://github.com/brianc/node-pg-types/blob/master/lib/builtins.js

通常はこの方法でアクセスできます

const pg = require('pg');

pg.types.setTypeParser(pg.types.builtins.INT8, (value: string) => {
   return parseInt(value);
});

pg.types.setTypeParser(pg.types.builtins.FLOAT8, (value: string) => {
    return parseFloat(value);
});

pg.types.setTypeParser(pg.types.builtins.NUMERIC, (value: string) => {
    return parseFloat(value);
});

その通常はすべての数値データを処理します。

何らかの理由で pg.types.builtins にアクセスできない場合 (私の場合、何らかの理由で typescript で)。それをコピーするだけです。または、対応するマップされた番号を直接使用します。

更新 (混乱を避けるため)

現在は "pg": "^7.11.0" です。pg は、ビルトインをまったく含まない pg-types 2.0.1 を使用しています。以前のすべてのバージョンも同様です。これにより、アクセスpg.types.builtins.が実行できなくなります (上記のバージョンまでのいずれのバージョンでも)。

前に述べた解決策は、現在のプロジェクトで行ったようにマッピングをコピーすることです。(上記のスニペットをすべてチェックしてコピーしてください) ここに画像の説明を入力 ここに画像の説明を入力

または、リストを指定して対応するマッピングを直接使用します。

pgp.pg.types.setTypeParser(20, parseInt);

回避策としての別の解決策は、pg-types パッケージを直接使用することです。それの最新バージョンです。

const types = require('pg-types');
// types.builtins.INT8

それ以外の場合は、次のリンクで確認できる @vitaly-t によって PR が埋められ
ます。

pg-typeswithingpgパッケージ (node-postgres) のバージョンを更新します。ここに画像の説明を入力

それで一旦受理。イニシャルの例が機能し始めます。

私のソースは当初、 httpspg-types : //github.com/brianc/node-pg-typesの公式の README であったことに注意してください。

ここに画像の説明を入力

 もう 1 つの最後の注意事項:

これはtypescriptの使用に関するものです。

pg-typestypescript の入力には、現在のバージョンのようにビルトインが含まれていません"pg-types": "^2.1.0"。更新予定です。したがって、自分で入力を追加するかのどちらかです。

typeof types & {builtins: {[key in builtinsTypes]: number}}

ここで、builtinsTypes はすべてのプロパティ名の結合です。

(ただし、穴オブジェクトをコピーして貼り付けると、より速く、より短く、よりきれいになります)。

次のように列挙型でそれを行うことができます

enum TypeId {
        BOOL = 16,
        BYTEA = 17,
        CHAR = 18,
        INT8 = 20,
        INT2 = 21,
        INT4 = 23,
        REGPROC = 24,
        TEXT = 25,
        OID = 26,
        TID = 27,
        XID = 28,
        CID = 29,
        JSON = 114,
        XML = 142,
        PG_NODE_TREE = 194,
        SMGR = 210,
        PATH = 602,
        POLYGON = 604,
        CIDR = 650,
        FLOAT4 = 700,
        FLOAT8 = 701,
        ABSTIME = 702,
        RELTIME = 703,
        TINTERVAL = 704,
        CIRCLE = 718,
        MACADDR8 = 774,
        MONEY = 790,
        MACADDR = 829,
        INET = 869,
        ACLITEM = 1033,
        BPCHAR = 1042,
        VARCHAR = 1043,
        DATE = 1082,
        TIME = 1083,
        TIMESTAMP = 1114,
        TIMESTAMPTZ = 1184,
        INTERVAL = 1186,
        TIMETZ = 1266,
        BIT = 1560,
        VARBIT = 1562,
        NUMERIC = 1700,
        REFCURSOR = 1790,
        REGPROCEDURE = 2202,
        REGOPER = 2203,
        REGOPERATOR = 2204,
        REGCLASS = 2205,
        REGTYPE = 2206,
        UUID = 2950,
        TXID_SNAPSHOT = 2970,
        PG_LSN = 3220,
        PG_NDISTINCT = 3361,
        PG_DEPENDENCIES = 3402,
        TSVECTOR = 3614,
        TSQUERY = 3615,
        GTSVECTOR = 3642,
        REGCONFIG = 3734,
        REGDICTIONARY = 3769,
        JSONB = 3802,
        REGNAMESPACE = 4089,
        REGROLE = 4096
}

https://github.com/vitaly-t/pg-promise/blob/v9/typescript/pg-subset.d.ts#L103内で行われたようにpg-promise

すべてが更新されたら。pg からの使用は道のりです。

アップデート

パッケージが更新されました。そして期待通りに使えます。

import { types } from 'pg';

// data parsing
types.setTypeParser(types.builtins.INT8, (value: string) => {
    return parseInt(value);
});

types.setTypeParser(types.builtins.FLOAT8, (value: string) => {
    return parseFloat(value);
});

types.setTypeParser(types.builtins.NUMERIC, (value: string) => {
    return parseFloat(value);
});

上記のvitaly-tの回答 のUPDATE-2の部分も確認してください https://stackoverflow.com/a/39176670/7668448

于 2019-07-25T21:41:23.427 に答える