Skip to main content

LargeObject

A PostgreSQL large object: binary data stored outside the row it belongs to, reached through a file-like interface so it can be seeked into and read a piece at a time instead of loaded whole the way a bytea column must be. A large object can hold up to 4TB, against roughly 1GB for bytea.

Instances are obtained from Connection.createLargeObject() or Connection.openLargeObject(); it is never constructed directly.

The descriptor a large object is opened with only lives as long as the transaction that opened it: createLargeObject()/openLargeObject() start one if the connection is not already in one, and close() commits that one, but never a transaction the caller started, which stays theirs to finish.

import { Connection } from 'postgrejs';
import { pipeline } from 'node:stream/promises';
import fs from 'node:fs';

const connection = new Connection('postgres://localhost');
await connection.connect();
const lo = await connection.createLargeObject();
await pipeline(fs.createReadStream('video.mp4'), lo.writable());
await lo.close();
// keep lo.oid somewhere - a large object belongs to no row
await connection.close();

Nothing links the object to any row that names it: dropping the row leaves the data behind, so Connection.unlinkLargeObject() has to be called when it is no longer wanted. PostgreSQL ships vacuumlo for finding the ones that were not.

Properties​

KeyTypeReadonlyDescription
oidnumbertrueOID of the large object

Methods​

read()​

Reads at most length bytes from the current position.

read(length: number): Promise<Buffer>

ArgumentTypeDefaultDescription
lengthnumberMaximum number of bytes to read
  • Returns a Buffer (possibly zero-length)

write()​

Writes at the current position.

write(data: Buffer): Promise<number>

ArgumentTypeDefaultDescription
dataBufferBytes to write
  • Returns the number of bytes written

seek()​

Moves the read/write position.

seek(offset: number | bigint, whence?: number): Promise<bigint>

ArgumentTypeDefaultDescription
offsetnumber | bigintOffset to seek by/to
whencenumber00 = from start, 1 = from current position, 2 = from end
  • Returns the new position

tell()​

Returns the current read/write position.

tell(): Promise<bigint>

size()​

Returns the total size in bytes. Leaves the position where it found it.

size(): Promise<bigint>

truncate()​

Cuts the object down to length bytes.

truncate(length: number | bigint): Promise<void>

ArgumentTypeDefaultDescription
lengthnumber | bigintNew size in bytes

readable()​

Returns a Node.js Readable that reads from the current position to the end.

readable(options?: LargeObjectStreamOptions): Readable

ArgumentTypeDefaultDescription
optionsLargeObjectStreamOptionsStream options

writable()​

Returns a Node.js Writable that writes from the current position onwards.

writable(options?: LargeObjectStreamOptions): Writable

ArgumentTypeDefaultDescription
optionsLargeObjectStreamOptionsStream options

close()​

Closes the descriptor, and commits the transaction if this object started it (see the note above). Safe to call more than once.

close(): Promise<void>

LargeObjectMode​

Open modes, mirroring PostgreSQL's own INV_READ / INV_WRITE constants. Passed to Connection.createLargeObject()/openLargeObject().

MemberValueDescription
read0x00040000Open for reading
write0x00020000Open for writing
readWrite0x00060000Open for both

LargeObjectStreamOptions​

Options for readable()/writable().

PropertyTypeDefaultDescription
chunkSizenumber65536Bytes per round trip. Each chunk is its own loread/lowrite call, trading memory for query count