LangChain JavaScript Integration

Use the @oracle/langchain-oracledb package to connect LangChain.js applications to Oracle AI Database. The package provides classes for vector storage, similarity search, document loading, text splitting, in-database embeddings, and summarization.

The examples in this guide use TypeScript syntax. The same APIs work from JavaScript when your project can import ES modules.

Package Overview

Install the Oracle package with LangChain core packages and the node-oracledb driver. Use Node.js 18 or later.

npm install @oracle/langchain-oracledb @langchain/core @langchain/textsplitters oracledb

If you prefer an external JavaScript embedding provider, install that provider package and pass the embedding instance to OracleVS.

Package What It Provides When to Use
@oracle/langchain-oracledb OracleVS, DistanceStrategy, VectorType, VectorElementFormat, createIndex, dropTablePurge, OracleDocLoader, OracleTextSplitter, OracleEmbeddings, OracleSummary Store and query vectors, create vector indexes, load documents with Oracle AI Database, split text, generate embeddings, and summarize content.
oracledb Oracle AI Database connectivity for Node.js. Connect with a single connection or connection pool.
@langchain/core LangChain document, embedding, vector store, and callback interfaces. Build chains and pass Document objects between LangChain components.
@langchain/textsplitters Base text splitter interfaces used by OracleTextSplitter. Use Oracle chunking with LangChain.js splitter workflows.

Connect to Oracle AI Database

Create a node-oracledb connection or pool and pass it to the Oracle classes. The vector store accepts either a Connection or a Pool; document loading, text splitting, embeddings, and summaries use a Connection.

import oracledb from "oracledb";

const connection = await oracledb.getConnection({
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  connectString: process.env.DB_CONNECT_STRING,
});

Use a pool for applications that serve concurrent requests.

import oracledb from "oracledb";

const pool = await oracledb.createPool({
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  connectString: process.env.DB_CONNECT_STRING,
  poolMin: 1,
  poolMax: 8,
});

Close a standalone connection after your application finishes.

await connection.close();

Close a pool during graceful shutdown.

await pool.close(0);

Quick Start

Create a vector store, insert documents, and run similarity search. The example uses a pool for OracleVS and a checked-out connection for OracleEmbeddings.

import oracledb from "oracledb";
import { Document } from "@langchain/core/documents";
import {
  DistanceStrategy,
  OracleEmbeddings,
  OracleVS,
  VectorElementFormat,
} from "@oracle/langchain-oracledb";

const pool = await oracledb.createPool({
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  connectString: process.env.DB_CONNECT_STRING,
});

const embeddingConnection = await pool.getConnection();

const embeddings = new OracleEmbeddings(embeddingConnection, {
  provider: "database",
  model: "doc_model",
});

const documents = [
  new Document({
    pageContent: "Oracle AI Database stores vectors with enterprise data.",
    metadata: { source: "overview", product: "oracle_ai_database" },
  }),
  new Document({
    pageContent: "LangChain.js applications can use OracleVS for similarity search.",
    metadata: { source: "quickstart", product: "langchain_js" },
  }),
];

const vectorStore = new OracleVS(embeddings, {
  client: pool,
  tableName: "LC_JS_VECTOR_STORE",
  query: "Oracle AI Database vector search",
  distanceStrategy: DistanceStrategy.COSINE,
  format: VectorElementFormat.FLOAT32,
});

await vectorStore.initialize();
await vectorStore.addDocuments(documents);

const results = await vectorStore.similaritySearch(
  "How do I use Oracle with LangChain.js?",
  2
);

for (const document of results) {
  console.log(document.pageContent, document.metadata);
}

await embeddingConnection.close();
await pool.close(0);

Vector Store

OracleVS stores text, metadata, and embedding vectors in an Oracle AI Database table. The initialize() method creates the table if it does not exist. The vector dimension is determined by embedding the query value supplied in the vector store configuration.

import {
  DistanceStrategy,
  OracleVS,
  VectorElementFormat,
  VectorType,
} from "@oracle/langchain-oracledb";

const vectorStore = new OracleVS(embeddings, {
  client: pool,
  tableName: "LC_JS_DOCS",
  query: "sample text used to determine embedding dimension",
  distanceStrategy: DistanceStrategy.COSINE,
  vectorType: VectorType.DENSE,
  format: VectorElementFormat.FLOAT32,
  description: "LangChain.js vector store",
  annotations: {
    text: "Original document text",
    metadata: "Document metadata as JSON",
    embedding: "Document embedding vector",
  },
});

await vectorStore.initialize();
Option Description
client oracledb.Connection or oracledb.Pool used for database calls.
tableName Table to create or reuse for vector storage.
query Sample text used to compute the embedding dimension during initialization.
distanceStrategy Distance metric used by similarity queries and vector indexes.
filter Optional default metadata filter.
description Optional table comment added during table creation.
annotations Optional column comments for generated table columns.
vectorType VectorType.DENSE or VectorType.SPARSE.
format Vector element format used for storage.

The generated table includes these columns:

Column Type Description
id RAW(16) Primary key generated by Oracle AI Database.
external_id VARCHAR2(36) Application-facing document ID.
embedding VECTOR(...) Vector generated from each document.
text CLOB Document text.
metadata JSON LangChain document metadata.

Distance Strategies and Vector Formats

Import constants from @oracle/langchain-oracledb rather than passing string literals throughout your code.

import {
  DistanceStrategy,
  VectorElementFormat,
  VectorType,
} from "@oracle/langchain-oracledb";
Constant Values
DistanceStrategy COSINE, DOT_PRODUCT, EUCLIDEAN, MANHATTAN, HAMMING, EUCLIDEAN_SQUARED
VectorType DENSE, SPARSE
VectorElementFormat FLOAT32, FLOAT64, INT8, BINARY, FLEX

Use dense FLOAT32 vectors for most embedding providers. Use sparse vectors only when your embedding model and search design require sparse vector storage. BINARY format requires the embedding dimension to be a multiple of 8 and is not valid for sparse vectors.

Add, Update, and Delete Documents

Add LangChain Document objects with generated IDs, explicit IDs, or metadata IDs.

import { Document } from "@langchain/core/documents";

const documents = [
  new Document({
    pageContent: "Oracle AI Vector Search supports similarity search.",
    metadata: { id: "doc-001", category: "vector-search" },
  }),
  new Document({
    pageContent: "LangChain.js provides a common vector store interface.",
    metadata: { id: "doc-002", category: "langchain" },
  }),
];

await vectorStore.addDocuments(documents);

Provide IDs directly when you want the caller to own document identity.

await vectorStore.addDocuments(documents, {
  ids: ["doc-001", "doc-002"],
});

Set mutateOnDuplicate to update existing rows that share the same external_id.

await vectorStore.addDocuments(documents, {
  ids: ["doc-001", "doc-002"],
  mutateOnDuplicate: true,
});

Delete specific internal IDs or truncate the vector store table.

await vectorStore.delete({ ids: [documentIdBuffer] });
await vectorStore.delete({ deleteAll: true });

Use dropTablePurge for development cleanup when you want to remove the table.

import { dropTablePurge } from "@oracle/langchain-oracledb";

await dropTablePurge(connection, "LC_JS_DOCS");

Use standard LangChain.js vector store methods for retrieval.

const documents = await vectorStore.similaritySearch(
  "What does OracleVS store?",
  4
);

Return scores with each result.

const scoredResults = await vectorStore.similaritySearchWithScore(
  "How can I store vectors?",
  4
);

for (const [document, score] of scoredResults) {
  console.log(score, document.pageContent);
}

Search from an embedding vector when you have already embedded the query.

const queryVector = await embeddings.embedQuery("Oracle vector indexes");
const scoredResults = await vectorStore.similaritySearchVectorWithScore(
  queryVector,
  4
);

Metadata Filtering

Metadata filters compile to JSON_EXISTS predicates against the vector store metadata column. Use simple equality, comparison operators, set operators, and Boolean composition.

const filteredResults = await vectorStore.similaritySearch(
  "Find LangChain content",
  5,
  {
    category: { $eq: "langchain" },
    year: { $gte: 2025 },
  }
);

Combine clauses with $and and $or.

const filteredResults = await vectorStore.similaritySearch(
  "Find vector search content",
  5,
  {
    $or: [
      { category: { $eq: "vector-search" } },
      { tags: { $in: ["retrieval", "rag"] } },
    ],
  }
);
Operator Example
$eq { category: { $eq: "rag" } }
$ne { status: { $ne: "archived" } }
$lt, $lte, $gt, $gte { year: { $gte: 2025 } }
$in, $nin { tags: { $in: ["rag", "search"] } }
$between { score: { $between: [0.5, 0.9] } }
$exists { author: { $exists: true } }
$and, $or { $and: [{ category: "rag" }, { year: { $gte: 2025 } }] }

Maximal Marginal Relevance

Use maximal marginal relevance (MMR) when search results should balance similarity and diversity.

const diverseDocuments = await vectorStore.maxMarginalRelevanceSearch(
  "Oracle AI Database retrieval patterns",
  {
    k: 4,
    fetchK: 20,
    lambda: 0.5,
    filter: { category: { $eq: "rag" } },
  }
);

Use a lower lambda value for more diversity. Use a higher value when similarity to the query is more important.

Create Vector Indexes

Use createIndex to create an HNSW or IVF vector index over the vector store table.

import { createIndex } from "@oracle/langchain-oracledb";

await createIndex(connection, vectorStore, {
  idxName: "LC_JS_DOCS_HNSW_IDX",
  idxType: "HNSW",
  neighbors: 32,
  efConstruction: 200,
  accuracy: 90,
  parallel: 8,
});

Create an IVF index when neighbor partition indexing fits your data size and refresh pattern.

await createIndex(connection, vectorStore, {
  idxName: "LC_JS_DOCS_IVF_IDX",
  idxType: "IVF",
  neighborPart: 64,
  accuracy: 90,
  parallel: 8,
});
Index Type Parameters
HNSW idxName, idxType, neighbors, efConstruction, accuracy, parallel
IVF idxName, idxType, neighborPart, accuracy, parallel

createIndex uses the vector store distanceStrategy for the index distance metric, so choose the distance strategy before initializing and indexing the vector store.

Document Loading

OracleDocLoader loads documents from a local file, a local directory, or an Oracle AI Database table. It uses Oracle AI Database document processing to extract plain text and metadata.

Load one file.

import { OracleDocLoader } from "@oracle/langchain-oracledb";

const loader = new OracleDocLoader(connection, {
  file: "./documents/overview.pdf",
});

const docs = await loader.load();

Load all files in a directory recursively.

const loader = new OracleDocLoader(connection, {
  dir: "./documents",
});

const docs = await loader.load();

Load documents from a table column.

const loader = new OracleDocLoader(connection, {
  owner: "VECTOR",
  tablename: "SOURCE_DOCUMENTS",
  colname: "FILE_CONTENT",
});

const docs = await loader.load();

When loading from a table, include owner, tablename, and colname in the loader preferences.

Text Splitting

OracleTextSplitter chunks text with Oracle AI Database. Pass chunking preferences supported by DBMS_VECTOR_CHAIN.UTL_TO_CHUNKS.

import { OracleTextSplitter } from "@oracle/langchain-oracledb";

const splitter = new OracleTextSplitter(connection, {
  split: "chars",
  max: 500,
  normalize: "all",
});

const chunks = await splitter.splitText(docs[0].pageContent);

Convert chunks back to LangChain Document objects before inserting them into a vector store.

import { Document } from "@langchain/core/documents";

const chunkDocuments = chunks.map((chunk, index) => {
  return new Document({
    pageContent: chunk,
    metadata: {
      ...docs[0].metadata,
      chunk_index: index,
    },
  });
});

await vectorStore.addDocuments(chunkDocuments);

In-Database Embeddings

OracleEmbeddings generates embeddings through Oracle AI Database. Use it when you want the database to call an embedding provider or an ONNX embedding model through DBMS_VECTOR_CHAIN.

import { OracleEmbeddings } from "@oracle/langchain-oracledb";

const embedder = new OracleEmbeddings(
  connection,
  {
    provider: "database",
    model: "doc_model",
  }
);

const vector = await embedder.embedQuery("Oracle AI Database vector search");
const vectors = await embedder.embedDocuments([
  "First document",
  "Second document",
]);

Load an ONNX model into Oracle AI Database before using it for in-database embeddings.

import { OracleEmbeddings } from "@oracle/langchain-oracledb";

await OracleEmbeddings.loadOnnxModel(
  connection,
  "DATA_PUMP_DIR",
  "all_MiniLM_L6_v2.onnx",
  "doc_model"
);

Pass a proxy string when the database must reach an external provider through an HTTP proxy.

const embedder = new OracleEmbeddings(
  connection,
  {
    provider: "ocigenai",
    credential_name: "OCI_CRED",
    url: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com",
    model: "cohere.embed-english-v3.0",
  },
  "http://proxy.example.com:80"
);

You can also use any LangChain-compatible JavaScript embedding model with OracleVS, as shown in the quick start.

Summarization

OracleSummary summarizes text through Oracle AI Database.

import { OracleSummary } from "@oracle/langchain-oracledb";

const summaryModel = new OracleSummary(
  connection,
  {
    provider: "database",
    model: "summary_model",
  }
);

const summary = await summaryModel.getSummary(docs[0].pageContent);

Pass a proxy string when the database calls an external summarization provider through a proxy.

const summaryModel = new OracleSummary(
  connection,
  {
    provider: "ocigenai",
    credential_name: "OCI_CRED",
    url: "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com",
    model: "cohere.command-r-plus",
  },
  "http://proxy.example.com:80"
);

End-to-End Ingestion Pipeline

Combine document loading, text splitting, embeddings, vector storage, and indexing.

import oracledb from "oracledb";
import { Document } from "@langchain/core/documents";
import {
  DistanceStrategy,
  OracleDocLoader,
  OracleEmbeddings,
  OracleTextSplitter,
  OracleVS,
  createIndex,
} from "@oracle/langchain-oracledb";

const pool = await oracledb.createPool({
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  connectString: process.env.DB_CONNECT_STRING,
});
const connection = await pool.getConnection();

const loader = new OracleDocLoader(connection, {
  dir: "./documents",
});
const loadedDocs = await loader.load();

const splitter = new OracleTextSplitter(connection, {
  split: "chars",
  max: 500,
  normalize: "all",
});

const chunks: Document[] = [];
for (const doc of loadedDocs) {
  const splitText = await splitter.splitText(doc.pageContent);
  splitText.forEach((chunk, index) => {
    chunks.push(
      new Document({
        pageContent: chunk,
        metadata: {
          ...doc.metadata,
          chunk_index: index,
        },
      })
    );
  });
}

const embeddings = new OracleEmbeddings(connection, {
  provider: "database",
  model: "doc_model",
});

const vectorStore = await OracleVS.fromDocuments(chunks, embeddings, {
  client: pool,
  tableName: "LC_JS_PIPELINE_DOCS",
  query: "sample text used to determine embedding dimension",
  distanceStrategy: DistanceStrategy.COSINE,
});

await createIndex(connection, vectorStore, {
  idxName: "LC_JS_PIPELINE_DOCS_HNSW_IDX",
  idxType: "HNSW",
});

const results = await vectorStore.similaritySearch(
  "Which documents discuss Oracle AI Database?",
  5
);

await connection.close();
await pool.close(0);

Operational Notes

Review these points before moving from a sample application to production:

Troubleshooting

Review these common issues before debugging application code.

Issue Cause Action
client parameter is required OracleVS.fromDocuments did not receive a client value. Pass an oracledb.Connection or oracledb.Pool in the vector store configuration.
Embedding dimension is required to create the vector column The vector store could not determine the embedding size. Provide a representative query string and verify that the embedding model returns vectors.
Vector length does not match the embedding dimension Documents were embedded with a different model or dimension than the table was initialized with. Reuse one embedding model per vector store table, or create a new table.
Sparse vector type requires a vector format to be specified VectorType.SPARSE was selected without a format. Set format to FLOAT32, FLOAT64, INT8, or FLEX.
BINARY vector format requires dimensions to be a multiple of 8 Binary vector storage packs bits into bytes. Use an embedding dimension divisible by 8 or choose another format.
Invalid owner, table, or column name OracleDocLoader rejected table loading identifiers. Check owner, tablename, and colname values.
No rows found Similarity search did not return rows for the query and filter. Insert documents, reduce filter constraints, or verify the embedding model.

Resources