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");
Similarity Search
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:
- Create one connection pool per application process and reuse it.
- Use explicit document IDs when the source system has stable primary keys.
- Use
mutateOnDuplicatefor repeatable ingestion jobs. - Create a vector index after bulk loading documents.
- Match
distanceStrategyto the embedding model and retrieval design. - Keep metadata values small and structured so JSON filtering remains predictable.
- Close pools and connections during graceful shutdown.
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
- LangChain.js OracleAI vector store documentation: Official LangChain.js vector store page.
- NPM:
@oracle/langchain-oracledb: JavaScript package for Oracle AI Database integrations. - Source:
@oracle/langchain-oracledbpackage: Package source code. - Oracle AI Vector Search documentation: Oracle vector search capabilities.
- Oracle AI Developer Hub: Notebooks, applications, and reference materials.