pgvector-node

repository·master·Indexed 19 days ago

https://github.com/pgvector/pgvector-node

Support for the pgvector extension in Node.js, Deno, and Bun (and TypeScript). It enables vector similarity search and storage within PostgreSQL, providing integration helpers for various database libraries and ORMs including node-postgres, Knex.js, Objection.js, Kysely, Sequelize, pg-promise, Prisma, Postgres.js, Slonik, TypeORM, MikroORM, and Drizzle ORM.

Tokens
15.7K
Snippets
61
Records
68
Agent score
64%

What's inside pgvector-node

  1. Use Drizzle ORM with pgvector

    master

    Drizzle ORM 0.31.0+ provides built-in support for vector, halfvec, bit, and sparsevec types. It also includes distance functions like l2Distance and cosineDistance.

    import { vector } from 'drizzle-orm/pg-core';
    import { l2Distance } from 'drizzle-orm';
    
    const items = pgTable('items', {
      id: serial('id').primaryKey(),
      embedding: vector('embedding', {dimensions: 3})
    });
    
    // Insert
    await db.insert(items).values([{embedding: [1, 2, 3]}]);
    
    // Query nearest neighbors
    const allItems = await db.select()
      .from(items)
      .orderBy(l2Distance(items.embedding, [1, 2, 3]))
      .limit(5);
  2. Use MikroORM with pgvector

    master

    MikroORM supports pgvector via the VectorType and specialized distance functions like l2Distance.

    import { VectorType } from 'pgvector/mikro-orm';
    import { l2Distance } from 'pgvector/mikro-orm';
    
    @Entity()
    class Item {
      @PrimaryKey()
      id: number;
    
      @Property({type: VectorType})
      embedding: number[];
    }
    
    // Insert
    em.create(Item, {embedding: [1, 2, 3]});
    
    // Query nearest neighbors
    const items = await em.createQueryBuilder(Item)
      .orderBy({[l2Distance('embedding', [1, 2, 3])]: 'ASC'})
      .limit(5)
      .getResult();
  3. Use deno-postgres with pgvector

    master

    For Deno environments, import the library via npm:pgvector and use queryArray for vector operations.

    import pgvector from 'npm:pgvector';
    
    // Enable extension
    await client.queryArray`CREATE EXTENSION IF NOT EXISTS vector`;
    
    // Insert
    const embedding = pgvector.toSql([1, 2, 3]);
    await client.queryArray`INSERT INTO items (embedding) VALUES (${embedding})`;
    
    // Query
    const { rows } = await client.queryArray`SELECT * FROM items ORDER BY embedding <-> ${embedding} LIMIT 5`;
  4. Use TypeORM with pgvector

    master

    TypeORM 0.3.27+ has built-in support for pgvector. You can define vector columns using the @Column decorator with the type 'vector' and a specified length.

    // Define an entity
    @Entity()
    class Item {
      @PrimaryGeneratedColumn()
      id: number
    
      @Column('vector', {length: 3})
      embedding: number[]
    }
    
    // Insert a vector
    const itemRepository = AppDataSource.getRepository(Item);
    await itemRepository.save({embedding: [1, 2, 3]});
    
    // Get nearest neighbors using QueryBuilder
    import pgvector from 'pgvector';
    const items = await itemRepository
      .createQueryBuilder('item')
      .orderBy('embedding <-> :embedding')
      .setParameters({embedding: pgvector.toSql([1, 2, 3])})
      .limit(5)
      .getMany();
  5. Use pgvector with Kysely

    master

    With Kysely, use pgvector/kysely for vector insertion and distance helpers. You can also use l2Distance within .where() clauses to find items within a specific distance.

    import pgvector from 'pgvector/kysely';
    import { l2Distance } from 'pgvector/kysely';
    
    // Enable extension
    await sql`CREATE EXTENSION IF NOT EXISTS vector`.execute(db);
    
    // Create table
    await db.schema.createTable('items')
      .addColumn('id', 'serial', (cb) => cb.primaryKey())
      .addColumn('embedding', sql`vector(3)`)
      .execute();
    
    // Insert vectors
    const newItems = [
      {embedding: pgvector.toSql([1, 2, 3])},
      {embedding: pgvector.toSql([4, 5, 6])}
    ];
    await db.insertInto('items').values(newItems).execute();
    
    // Get nearest neighbors
    const items = await db.selectFrom('items')
      .selectAll()
      .orderBy(l2Distance('embedding', [1, 2, 3]))
      .limit(5)
      .execute();
    
    // Get items within a certain distance
    const itemsInRange = await db.selectFrom('items')
      .selectAll()
      .where(l2Distance('embedding', [1, 2, 3]), '<', 5)
      .execute();
    
    // Add an approximate index
    await db.schema.createIndex('index_name')
      .on('items')
      .using('hnsw')
      .expression(sql`embedding vector_l2_ops")
      .execute();
  6. Use pgvector with pg-promise

    master

    For pg-promise, import pgvector/pg-promise and use the connect option in the initialization to register types on the client.

    import pgpromise from 'pg-promise';
    import pgvector from 'pgvector/pg-promise';
    
    const initOptions = {
      async connect(e) {
        await pgvector.registerTypes(e.client);
      }
    };
    const pgp = pgpromise(initOptions);
    const db = pgp.connect();
    
    // Enable extension
    await db.none('CREATE EXTENSION IF NOT EXISTS vector');
    
    // Insert a vector
    await db.none('INSERT INTO items (embedding) VALUES ($1)', [pgvector.toSql([1, 2, 3])]);
    
    // Get nearest neighbors
    const result = await db.any('SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 5', [pgvector.toSql([1, 2, 3])]);
  7. Use pgvector with Postgres.js

    master

    With Postgres.js, import pgvector and use pgvector.toSql() to format arrays for insertion and distance queries within template literals.

    import pgvector from 'pgvector';
    
    // Enable extension
    await sql`CREATE EXTENSION IF NOT EXISTS vector`;
    
    // Create table
    await sql`CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3))`;
    
    // Insert vectors
    const newItems = [
      {embedding: pgvector.toSql([1, 2, 3])},
      {embedding: pgvector.toSql([4, 5, 6])}
    ];
    await sql`INSERT INTO items ${ sql(newItems, 'embedding') }`;
    
    // Get nearest neighbors
    const embedding = pgvector.toSql([1, 2, 3]);
    const items = await sql`SELECT * FROM items ORDER BY embedding <-> ${ embedding } LIMIT 5`;
    
    // Add an approximate index
    await sql`CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)`;
  8. Use pgvector with Prisma

    master

    Prisma requires specific configuration to support pgvector.

    Note: prisma migrate dev does not currently support pgvector indexes.

    1. Enable the postgresqlExtensions preview feature in your generator.
    2. Add vector to the extensions list in your datasource.
    3. Use Unsupported("vector(n)") for the column type.
    4. Use pgvector.toSql() and raw queries ($executeRaw or $queryRaw) for vector operations.
    // schema.prisma
    generator client {
      provider        = "prisma-client"
      previewFeatures = ["postgresqlExtensions"]
    }
    
    datasource db {
      provider   = "postgresql"
      extensions = [vector]
    }
    
    model Item {
      id        Int                       @id @default(autoincrement())
      embedding Unsupported("vector(3)")?
    }
    import pgvector from 'pgvector';
    
    const embedding = pgvector.toSql([1, 2, 3]);
    
    // Insert
    await prisma.$executeRaw`INSERT INTO items (embedding) VALUES (${embedding}::vector)`;
    
    // Query
    const items = await prisma.$queryRaw`SELECT id, embedding::text FROM items ORDER BY embedding <-> ${embedding}::vector LIMIT 5`;
  9. Use Slonik with pgvector

    master

    To use pgvector with Slonik, import the library, enable the extension using sql.unsafe, and use pgvector.toSql() to format arrays for insertion or distance queries.

    import pgvector from 'pgvector';
    
    // Enable the extension
    await pool.query(sql.unsafe`CREATE EXTENSION IF NOT EXISTS vector`);
    
    // Create a table
    await pool.query(sql.unsafe`CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))`);
    
    // Insert a vector
    const embedding = pgvector.toSql([1, 2, 3]);
    await pool.query(sql.unsafe`INSERT INTO items (embedding) VALUES (${embedding})`);
    
    // Get the nearest neighbors
    const items = await pool.query(sql.unsafe`SELECT * FROM items ORDER BY embedding <-> ${embedding} LIMIT 5`);
    
    // Add an approximate index
    await pool.query(sql.unsafe`CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)`);
  10. Use pgvector with Knex.js

    master

    Integrate pgvector with Knex.js by importing pgvector/knex. It provides helper methods for schema creation, vector column definitions, and distance calculations like l2Distance, cosineDistance, maxInnerProduct, l1Distance, hammingDistance, and jaccardDistance.

    import pgvector from 'pgvector/knex';
    
    // Enable extension
    await knex.schema.createExtensionIfNotExists('vector');
    
    // Create table with vector column
    await knex.schema.createTable('items', (table) => {
      table.increments('id');
      table.vector('embedding', 3);
    });
    
    // Insert vectors
    const newItems = [
      {embedding: pgvector.toSql([1, 2, 3])},
      {embedding: pgvector.toSql([4, 5, 6])}
    ];
    await knex('items').insert(newItems);
    
    // Get nearest neighbors using l2Distance
    const items = await knex('items')
      .orderBy(knex.l2Distance('embedding', [1, 2, 3]))
      .limit(5);
    
    // Add an approximate index
    await knex.schema.alterTable('items', function (table) {
      table.index([knex.raw('embedding vector_l2_ops')], 'index_name', 'hnsw');
    });
  11. Use Bun SQL with pgvector

    master

    When using Bun SQL, import pgvector and use pgvector.toSql() to prepare arrays for insertion or distance-based ordering.

    import pgvector from 'pgvector';
    
    // Insert multiple
    const newItems = [
      {embedding: pgvector.toSql([1, 2, 3])},
      {embedding: pgvector.toSql([4, 5, 6])}
    ];
    await sql`INSERT INTO items ${sql(newItems)}`;
    
    // Query
    const embedding = pgvector.toSql([1, 2, 3]);
    const items = await sql`SELECT * FROM items ORDER BY embedding <-> ${embedding} LIMIT 5`.values();