A MemberJunction implementation of vector database services using Pinecone as the backend. This package provides a standardized interface for working with vector embeddings, vector search, and other vector operations within the MemberJunction ecosystem.
npm install @memberjunction/ai-vectors-pinecone
Create a .env file with your Pinecone credentials:
# Pinecone Configuration
PINECONE_API_KEY=your-pinecone-api-key
PINECONE_HOST=your-pinecone-host
PINECONE_DEFAULT_INDEX=your-default-index-name
# Optional: For embedding generation
OPENAI_API_KEY=your-openai-api-key
# Optional: Database configuration (if using with MemberJunction sync)
DB_HOST=your-database-host
DB_PORT=1433
DB_USERNAME=your-db-username
DB_PASSWORD=your-db-password
DB_DATABASE=your-database-name
import { PineconeDatabase } from '@memberjunction/ai-vectors-pinecone';
// Initialize with your Pinecone API key
const pineconeDB = new PineconeDatabase('your-pinecone-api-key');
// Get a list of all available indexes
const indexList = await pineconeDB.listIndexes();
console.log('Available indexes:', indexList.indexes.map(idx => idx.name));
// Create a new vector index with serverless configuration
const createResult = await pineconeDB.createIndex({
id: 'my-new-index',
dimension: 1536, // Dimension for OpenAI embeddings
metric: 'cosine', // 'cosine' | 'euclidean' | 'dotproduct'
additionalParams: {
// Pinecone spec object
serverless: {
cloud: 'aws',
region: 'us-west-2'
}
}
});
if (createResult.success) {
console.log('Index created successfully');
} else {
console.error('Failed to create index:', createResult.message);
}
// Get index description
const description = await pineconeDB.getIndexDescription({ id: 'my-new-index' });
console.log('Index details:', description);
import { VectorRecord } from '@memberjunction/ai-vectors';
// Create a single vector record
const vectorRecord: VectorRecord = {
id: 'record-123',
values: [0.1, 0.2, 0.3, /* ... rest of vector values */],
metadata: {
RecordID: '123',
Entity: 'Customer',
TemplateID: 'customer-profile',
// Additional metadata as needed
}
};
const insertResult = await pineconeDB.createRecord(vectorRecord);
if (insertResult.success) {
console.log('Record inserted successfully');
}
// Create multiple vector records in a single operation
const vectorRecords: VectorRecord[] = [
{
id: 'record-123',
values: [/* vector values */],
metadata: { RecordID: '123', Entity: 'Customer', TemplateID: 'template-1' }
},
{
id: 'record-124',
values: [/* vector values */],
metadata: { RecordID: '124', Entity: 'Customer', TemplateID: 'template-1' }
}
];
const batchInsertResult = await pineconeDB.createRecords(vectorRecords);
// Query vectors by similarity
const queryResult = await pineconeDB.queryIndex({
vector: [0.1, 0.2, 0.3, /* ... rest of query vector */],
topK: 5,
includeMetadata: true,
filter: {
Entity: { $eq: 'Customer' }
}
});
if (queryResult.success) {
console.log('Query results:', queryResult.data.matches);
// Process the matching records
queryResult.data.matches.forEach(match => {
console.log(`Match ID: ${match.id}, Score: ${match.score}`);
console.log('Metadata:', match.metadata);
});
}
// Fetch specific records by IDs
const getRecordResult = await pineconeDB.getRecord({
id: 'my-index-name', // Optional - uses default if not specified
data: ['record-123'] // Array of record IDs to fetch
});
if (getRecordResult.success) {
console.log('Retrieved records:', getRecordResult.data);
}
// Fetch multiple records at once
const getMultipleResult = await pineconeDB.getRecords({
data: ['record-123', 'record-124', 'record-125']
});
if (getMultipleResult.success) {
console.log('Retrieved records:', getMultipleResult.data);
}
// Update a record's values and/or metadata
const updateResult = await pineconeDB.updateRecord({
data: {
id: 'record-123',
values: [0.2, 0.3, 0.4, /* ... new vector values */],
setMetadata: {
// Metadata fields to update
TemplateID: 'updated-template'
}
}
});
if (updateResult.success) {
console.log('Record updated successfully');
}
// Delete a single record
const deleteResult = await pineconeDB.deleteRecord({
id: 'record-123'
});
// Delete multiple records
const deleteMultipleResult = await pineconeDB.deleteRecords([
{ id: 'record-123' },
{ id: 'record-124' }
]);
// Delete all records in an index or namespace
const deleteAllResult = await pineconeDB.deleteAllRecords({
id: 'my-index-name', // Optional - uses default if not specified
data: 'my-namespace' // Optional - if provided, only deletes in this namespace
});
Pinecone supports namespaces for organizing vectors within an index. This is useful for multi-tenancy or logical separation of data:
// Query within a specific namespace
const namespaceQuery = await pineconeDB.queryIndex({
vector: [/* query vector */],
topK: 10,
namespace: 'customer-data',
includeMetadata: true
});
// Delete all records in a specific namespace
const deleteNamespace = await pineconeDB.deleteAllRecords({
data: 'customer-data' // Deletes only in this namespace
});
// Query with complex metadata filters
const filteredQuery = await pineconeDB.queryIndex({
vector: [/* query vector */],
topK: 5,
filter: {
// Pinecone filter syntax
$and: [
{ Entity: { $eq: 'Customer' } },
{ TemplateID: { $in: ['template-1', 'template-2'] } },
{ RecordID: { $gte: '100' } }
]
},
includeMetadata: true,
includeValues: false // Don't return vector values to save bandwidth
});
The main class that implements the VectorDBBase abstract class for Pinecone.
new PineconeDatabase(apiKey: string)
pinecone: Returns the underlying Pinecone client instancelistIndexes(): List all available indexesgetIndexDescription(params): Get detailed information about an indexcreateIndex(options): Create a new vector indexdeleteIndex(params): Delete an indexgetIndex(params?): Get a reference to an index (uses default if not specified)getDefaultIndex(): Get the default index based on config or first availablecreateRecord(params): Insert a single vector recordcreateRecords(records): Insert multiple vector recordsgetRecord(params): Retrieve records by ID(s)getRecords(params): Retrieve multiple records by ID(s)updateRecord(params): Update a single record's values and/or metadatadeleteRecord(record): Delete a specific recorddeleteRecords(records): Delete multiple recordsdeleteAllRecords(params): Delete all records in an index or namespacequeryIndex(params): Query vectors by similarityeditIndex(params): Edit index configuration (throws error)updateRecords(params): Batch update records (throws error)interface VectorRecord {
id: string;
values: number[];
metadata?: RecordMetadata;
sparseValues?: { indices: number[]; values: number[] };
}
interface BaseRequestParams {
id?: string; // Index name (uses default if not provided)
data?: any; // Additional data for the operation
}
interface CreateIndexParams {
id: string; // Index name
dimension: number; // Vector dimension
metric?: string; // Distance metric (cosine, euclidean, dotproduct)
additionalParams?: any; // Additional Pinecone-specific parameters (spec object)
}
interface QueryOptions {
vector: number[]; // Query vector
topK: number; // Number of results to return
filter?: object; // Metadata filter
includeValues?: boolean; // Include vector values in response
includeMetadata?: boolean;// Include metadata in response
namespace?: string; // Namespace to query
}
type BaseMetadata = {
RecordID: string;
Entity: string;
TemplateID: string;
}
| Variable | Description |
|---|---|
| PINECONE_API_KEY | Your Pinecone API key (required) |
| PINECONE_HOST | Your Pinecone host URL (optional) |
| PINECONE_DEFAULT_INDEX | Default index name to use if not specified (optional) |
| OPENAI_API_KEY | Optional: OpenAI API key for generating embeddings |
| DB_HOST | Optional: Database host for MemberJunction sync |
| DB_PORT | Optional: Database port (defaults to 1433) |
| DB_USERNAME | Optional: Database username |
| DB_PASSWORD | Optional: Database password |
| DB_DATABASE | Optional: Database name |
| CURRENT_USER_EMAIL | Optional: Current user email for context |
| MISTRAL_API_KEY | Optional: Mistral API key for embeddings |
This package works seamlessly with other MemberJunction vector packages:
import { PineconeDatabase, LoadPineconeVectorDB } from '@memberjunction/ai-vectors-pinecone';
import { OpenAIEmbedding } from '@memberjunction/ai-openai';
import { VectorSync } from '@memberjunction/ai-vectors-sync';
// Ensure the PineconeDatabase class is registered
LoadPineconeVectorDB();
// Set up your vector database
const vectorDB = new PineconeDatabase(pineconeAPIKey);
// Set up your embedding provider
const embeddingProvider = new OpenAIEmbedding(openAIAPIKey);
// Use with VectorSync for entity synchronization
const vectorSync = new VectorSync({
vectorDB: vectorDB,
embeddingProvider: embeddingProvider,
// other configuration...
});
The PineconeDatabase class automatically registers itself with MemberJunction's class factory system using the @RegisterClass decorator. This allows it to be dynamically instantiated by the MemberJunction framework when needed.
To ensure the class is not removed by tree shaking, import the LoadPineconeVectorDB function in your application initialization:
import { LoadPineconeVectorDB } from '@memberjunction/ai-vectors-pinecone';
// Call this in your app initialization
LoadPineconeVectorDB();
All methods return a BaseResponse object with success/failure status:
const result = await pineconeDB.createRecord(vectorRecord);
if (result.success) {
console.log('Operation successful:', result.data);
} else {
console.error('Operation failed:', result.message);
// Handle error appropriately
}
Index Management
Vector Dimensions
Metadata Design
Batch Operations
createRecords() for bulk inserts (more efficient than individual inserts)Query Optimization
includeValues: false if you don't need vector valuestopK based on your use caseConnection Management
@memberjunction/ai-vectors: Base abstractions for vector databases@memberjunction/aiengine: MemberJunction AI Engine@memberjunction/core: MemberJunction core library@memberjunction/global: MemberJunction global utilities and class registration@pinecone-database/pinecone: Official Pinecone client (v2.2.2)dotenv: Environment variable managementopenai: OpenAI SDK for embeddingsrxjs: Reactive programming librarytypeorm: TypeORM for database operations"PINECONE_API_KEY not found"
.env file is in the project root"Index not found"
listIndexes()"Dimension mismatch"
Connection timeouts
Tree shaking removes the class
LoadPineconeVectorDB() in your initialization codeISC