簡體   English   中英

如何從 Express REST API 查詢 Postgres 表中的 JSON

[英]How to query JSON in a Postgres table from an Express REST API

我正在嘗試通過 Express REST API 查詢 Postgres 數據庫。一列 (json_object_data) 包括 json,我希望在其上查詢“名稱”鍵。

如果我直接在數據庫控制台中輸入查詢,它就可以正常工作。 給我帶來問題的是將搜索詞傳遞到 HTTP 對 Express 路線的請求中。

僅供參考,其他不嘗試查詢 json 列的 Express 應用程序請求(GET、POST、PUT 和 DELETE)工作正常。

節點快遞代碼:

app.get("/authorsname/:name", async(req, res) => {
    const { author_name } = req.params;
    console.log(req.params);
    try {
        const getAuthors = await pool.query("select json_object_data from \"jason-elwood/authors\".\"authors\" where lower(json_object_data ->> 'name') like lower($1%)", [author_name]);
        res.json(getAuthors);
        console.log(req.params);
    } catch (error) {
           console.error(error.message); 
    }
});

示例 json(來自 json_object_data 列):

{
    "name": "Jason Elwood", 
    "personal_name": "Jason Elwood", 
    "last_modified": {"type": "/type/datetime", "value": "2008-08-20T17:57:31.650087"}, 
    "key": "/authors/OL1000204A", 
    "birth_date": "1982", 
    "type": {"key": "/type/author"}, 
    "revision": 2
}

http GET請求:

http://localhost:3000/authorsname/jason

結果:

server is listening on port 3000
{ name: 'jason' }
node:events:371
      throw er; // Unhandled 'error' event
      ^

error: unable to bind
    at Parser.parseErrorMessage (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/parser.js:287:98)
    at Parser.handlePacket (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/parser.js:126:29)
    at Parser.parse (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/parser.js:39:38)
    at Socket.<anonymous> (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/index.js:11:42)
    at Socket.emit (node:events:394:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Socket.Readable.push (node:internal/streams/readable:228:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:199:23)
Emitted 'error' event on BoundPool instance at:
    at Client.idleListener (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-pool/index.js:57:10)
    at Client.emit (node:events:394:28)
    at Client._handleErrorEvent (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg/lib/client.js:319:10)
    at Client._handleErrorMessage (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg/lib/client.js:330:12)
    at Connection.emit (node:events:394:28)
    at /Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg/lib/connection.js:114:12
    at Parser.parse (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/parser.js:40:17)
    at Socket.<anonymous> (/Users/jasonelwood/Development/OpenbookAPIs/node_modules/pg-protocol/dist/index.js:11:42)
    at Socket.emit (node:events:394:28)
    at addChunk (node:internal/streams/readable:315:12) {
  length: 92,
  severity: 'FATAL',
  code: 'XX000',
  detail: 'cannot get parse message ""',
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'pool_proto_modules.c',
  line: '1414',
  routine: undefined,
  client: Client {
    _events: [Object: null prototype] { error: [Function (anonymous)] },
    _eventsCount: 1,
    _maxListeners: undefined,
    connectionParameters: ConnectionParameters {
      user: 'omitted',
      database: 'omitted',
      port: 5432,
      host: 'omitted',
      binary: false,
      options: undefined,
      ssl: false,
      client_encoding: '',
      replication: undefined,
      isDomainSocket: false,
      application_name: undefined,
      fallback_application_name: undefined,
      statement_timeout: false,
      idle_in_transaction_session_timeout: false,
      query_timeout: false,
      connect_timeout: 0
    },
    user: 'omitted',
    database: 'omitted',
    port: 5432,
    host: 'omitted',
    replication: undefined,
    _Promise: [Function: Promise],
    _types: TypeOverrides {
      _types: {
        getTypeParser: [Function: getTypeParser],
        setTypeParser: [Function: setTypeParser],
        arrayParser: { create: [Function: create] },
        builtins: {
          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
        }
      },
      text: {},
      binary: {}
    },
    _ending: true,
    _connecting: false,
    _connected: true,
    _connectionError: false,
    _queryable: false,
    connection: Connection {
      _events: [Object: null prototype] {
        newListener: [Function (anonymous)],
        connect: [Function (anonymous)],
        sslconnect: [Function (anonymous)],
        authenticationCleartextPassword: [Function: bound _handleAuthCleartextPassword],
        authenticationMD5Password: [Function: bound _handleAuthMD5Password],
        authenticationSASL: [Function: bound _handleAuthSASL],
        authenticationSASLContinue: [Function: bound _handleAuthSASLContinue],
        authenticationSASLFinal: [Function: bound _handleAuthSASLFinal],
        backendKeyData: [Function: bound _handleBackendKeyData],
        error: [Function: bound _handleErrorEvent],
        errorMessage: [Function: bound _handleErrorMessage],
        readyForQuery: [Function: bound _handleReadyForQuery],
        notice: [Function: bound _handleNotice],
        rowDescription: [Function: bound _handleRowDescription],
        dataRow: [Function: bound _handleDataRow],
        portalSuspended: [Function: bound _handlePortalSuspended],
        emptyQuery: [Function: bound _handleEmptyQuery],
        commandComplete: [Function: bound _handleCommandComplete],
        parseComplete: [Function: bound _handleParseComplete],
        copyInResponse: [Function: bound _handleCopyInResponse],
        copyData: [Function: bound _handleCopyData],
        notification: [Function: bound _handleNotification],
        end: [
          [Function: bound onceWrapper] {
            listener: [Function (anonymous)]
          },
          [Function: bound onceWrapper] {
            listener: [Function (anonymous)]
          },
          [Function: bound onceWrapper] {
            listener: [Function (anonymous)]
          }
        ]
      },
      _eventsCount: 23,
      _maxListeners: undefined,
      stream: <ref *1> Socket {
        connecting: false,
        _hadError: false,
        _parent: null,
        _host: 'db.bit.io',
        _readableState: ReadableState {
          objectMode: false,
          highWaterMark: 16384,
          buffer: BufferList { head: null, tail: null, length: 0 },
          length: 0,
          pipes: [],
          flowing: true,
          ended: false,
          endEmitted: false,
          reading: false,
          constructed: true,
          sync: false,
          needReadable: true,
          emittedReadable: false,
          readableListening: false,
          resumeScheduled: false,
          errorEmitted: false,
          emitClose: false,
          autoDestroy: true,
          destroyed: true,
          errored: null,
          closed: true,
          closeEmitted: false,
          defaultEncoding: 'utf8',
          awaitDrainWriters: null,
          multiAwaitDrain: false,
          readingMore: false,
          dataEmitted: true,
          decoder: null,
          encoding: null,
          [Symbol(kPaused)]: false
        },
        _events: [Object: null prototype] {
          end: [
            [Function: onReadableStreamEnd],
            [Function (anonymous)],
            [Function (anonymous)]
          ],
          error: [Function: reportStreamError],
          close: [Function (anonymous)],
          data: [Function (anonymous)]
        },
        _eventsCount: 4,
        _maxListeners: undefined,
        _writableState: <ref *2> WritableState {
          objectMode: false,
          highWaterMark: 16384,
          finalCalled: false,
          needDrain: false,
          ending: false,
          ended: false,
          finished: false,
          destroyed: true,
          decodeStrings: false,
          defaultEncoding: 'utf8',
          length: 0,
          writing: false,
          corked: 0,
          sync: false,
          bufferProcessing: false,
          onwrite: [Function: bound onwrite],
          writecb: null,
          writelen: 0,
          afterWriteTickInfo: {
            count: 1,
            cb: [Function (anonymous)],
            stream: [Circular *1],
            state: [Circular *2]
          },
          buffered: [],
          bufferedIndex: 0,
          allBuffers: true,
          allNoop: true,
          pendingcb: 1,
          constructed: true,
          prefinished: false,
          errorEmitted: false,
          emitClose: false,
          autoDestroy: true,
          errored: null,
          closed: true,
          closeEmitted: false,
          [Symbol(kOnFinished)]: []
        },
        allowHalfOpen: false,
        _sockname: null,
        _pendingData: null,
        _pendingEncoding: '',
        server: null,
        _server: null,
        [Symbol(async_id_symbol)]: 22,
        [Symbol(kHandle)]: null,
        [Symbol(kSetNoDelay)]: true,
        [Symbol(lastWriteQueueSize)]: 0,
        [Symbol(timeout)]: null,
        [Symbol(kBuffer)]: null,
        [Symbol(kBufferCb)]: null,
        [Symbol(kBufferGen)]: null,
        [Symbol(kCapture)]: false,
        [Symbol(kBytesRead)]: 784,
        [Symbol(kBytesWritten)]: 297
      },
      _keepAlive: false,
      _keepAliveInitialDelayMillis: 0,
      lastBuffer: false,
      parsedStatements: {},
      ssl: false,
      _ending: true,
      _emitMessage: false,
      _connecting: true,
      [Symbol(kCapture)]: false
    },
    queryQueue: [],
    binary: false,
    processID: -1631365830,
    secretKey: -1498717443,
    ssl: false,
    _connectionTimeoutMillis: 0,
    _connectionCallback: null,
    release: [Function (anonymous)],
    activeQuery: null,
    readyForQuery: true,
    hasExecuted: true,
    _poolUseCount: 1,
    [Symbol(kCapture)]: false
  }
}
[nodemon] app crashed - waiting for file changes before starting...

直接在數據庫控制台中發出相同的請求(產生成功的響應):

select json_object_data from "jason-elwood/authors"."authors" where lower(json_object_data ->> 'name') like lower('jason%');

我猜這與查詢的結構有關,尤其是我在請求字符串中包含請求參數的方式。 我嘗試將整個請求用單引號引起來,而不是 escaping 表名,如下所示:

const getAuthors = await pool.query('select json_object_data from "jason-elwood/authors"."authors" where lower(json_object_data ->> "name") like lower($1%)', [author_name]);

但它仍然會產生錯誤。

非常感謝對此的任何幫助。

謝謝!

至少應將%添加到傳遞的值中,因為您使用查詢參數:

const getAuthors = await pool
  .query("select json_object_data from \"jason-elwood/authors\".\"authors\" where json_object_data ->> 'name' ilike $1", [`${author_name}%`]);
res.json(getAuthors);

並且您可以使用ilike而不是like來避免在操作的兩邊都使用lower

因此,對於將來遇到此問題的任何其他人來說,問題在於我在將參數添加到查詢字符串時如何構建參數。 因為我使用的是 LIKE 運算符,所以需要像這樣格式化:

['%' + req.params.name + '%']

在我的頭撞在桌子上幾個小時后,現在對我來說顯而易見的原因。 (或者我最初擁有的是 ['%' + author_name + '%'])。 所以最終的查詢看起來像這樣:

const getAuthors = await pool.query("select json_object_data from \"jason-elwood/authors\".\"authors\" where lower(json_object_data ->> 'name') like lower($1)", ['%' + req.params.name + '%']);

我又可以呼吸了。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM