Adds new vectors to the encrypted index or updates existing vectors if they have the same ID. This operation supports two distinct calling patterns for maximum flexibility.

Method Overloads

Pattern 1: VectorItem Array

async upsert({
    items?: VectorItem[],    // optional, required if ids and vectors not provided
    ids?: string[],         // optional, used for bulk operations
    vectors?: number[][]    // optional, used for bulk operations
}): Promise<object>

Parameters

Pattern 1: VectorItem Array

ParameterTypeDescription
itemsVectorItem[]Array of vector items to insert or update in the index

Pattern 2: Parallel Arrays

ParameterTypeDescription
idsstring[]Array of ID strings for each vector
vectorsnumber[][]Array of vector embeddings corresponding to each ID

VectorItem Structure

Each VectorItem must contain an id and vector, with optional fields:
FieldTypeRequiredDescription
idstringYesUnique identifier for the vector item
vectornumber[]YesThe vector representation
contentsstring | BufferOptionalOriginal text or binary content associated with the vector
metadataobjectOptionalAdditional structured data associated with the vector

Returns

Promise<object>: A Promise that resolves to a response object containing the operation status and message with the count of upserted vectors.

Exceptions

Example Usage

import { Client, VectorItem } from 'cyborgdb';

const client = new Client({ baseUrl: 'http://localhost:8000', apiKey: 'your-api-key' });

// Load an existing index
const indexKey = new Uint8Array(Buffer.from('your-stored-hex-key', 'hex'));
const index = await client.loadIndex({ indexName: 'my-vector-index', indexKey });

// Prepare vector items with rich metadata
const vectorItems: VectorItem[] = [
    {
        id: 'doc1',
        vector: [0.1, 0.2, 0.3, /* ... additional dimensions */],
        contents: 'This is the content of the first document',
        metadata: {
            title: 'Introduction to Machine Learning',
            author: 'Dr. Smith',
            category: 'education',
            tags: ['ml', 'ai', 'tutorial'],
            published_date: '2024-01-15',
            word_count: 1250
        }
    },
    {
        id: 'doc2',
        vector: [0.4, 0.5, 0.6, /* ... additional dimensions */],
        contents: 'This is the content of the second document',
        metadata: {
            title: 'Advanced Neural Networks',
            author: 'Dr. Jones',
            category: 'research',
            tags: ['neural-networks', 'deep-learning'],
            published_date: '2024-01-20',
            word_count: 2100
        }
    }
];

// Upsert vectors
try {
    const result = await index.upsert(vectorItems);
    console.log('Upsert result:', result);
    // Typical output: { status: 'success', message: 'Upserted 2 vectors' }
    
    console.log(`Successfully added ${vectorItems.length} vectors to the index`);
} catch (error: any) {
    console.error('Upsert failed:', error.message);
}

Pattern 2: Parallel Arrays (For Bulk Operations)

// Efficient for bulk operations with just IDs and vectors
const ids = ['vec1', 'vec2', 'vec3'];
const vectors = [
    [0.1, 0.2, 0.3, 0.4],
    [0.5, 0.6, 0.7, 0.8],
    [0.9, 1.0, 1.1, 1.2]
];

try {
    const result = await index.upsert(ids, vectors);
    console.log('Bulk upsert result:', result);
    
    // This approach is more efficient for large datasets
    // where you only need IDs and vectors (no metadata/contents)
} catch (error: any) {
    console.error('Bulk upsert failed:', error.message);
}

Updating Existing Vectors

// Add initial vector
const initialVector: VectorItem = {
    id: 'updatable_doc',
    vector: [0.1, 0.2, 0.3, 0.4],
    contents: 'Original content',
    metadata: { version: 1, status: 'draft' }
};

await index.upsert([initialVector]);

// Update the same vector with new data
const updatedVector: VectorItem = {
    id: 'updatable_doc', // Same ID - will update existing
    vector: [0.15, 0.25, 0.35, 0.45], // Updated vector
    contents: 'Updated content with more information',
    metadata: { 
        version: 2, 
        status: 'published', 
        updated_date: '2024-01-25',
        editor: 'John Doe'
    }
};

try {
    const updateResult = await index.upsert([updatedVector]);
    console.log('Update result:', updateResult);
    
    // Verify the update
    const retrievedVector = await index.get({ ids: ['updatable_doc'] });
    console.log('Updated vector metadata:', retrievedVector[0].metadata);
} catch (error: any) {
    console.error('Update failed:', error.message);
}

Batch Processing with Error Handling

async function processBatchDocuments(
    index: EncryptedIndex, 
    documents: Array<{
        id: string;
        title: string;
        content: string;
        author: string;
        category: string;
        vector: number[];
    }>
): Promise<{ success: boolean; count: number; message: string }> {
    
    // Convert documents to VectorItem format
    const vectorItems: VectorItem[] = documents.map(doc => ({
        id: doc.id,
        vector: doc.vector,
        contents: doc.content,
        metadata: {
            title: doc.title,
            author: doc.author,
            category: doc.category,
            word_count: doc.content.split(' ').length,
            char_count: doc.content.length,
            processed_date: new Date().toISOString()
        }
    }));
    
    try {
        console.log(`Processing batch of ${vectorItems.length} documents`);
        
        const result = await index.upsert(vectorItems);
        console.log('Batch upsert completed:', result);
        
        return {
            success: true,
            count: vectorItems.length,
            message: `Successfully processed ${vectorItems.length} documents`
        };
    } catch (error: any) {
        console.error('Batch upsert failed:', error.message);
        
        // Provide detailed error information
        if (error.message.includes('Invalid VectorItem')) {
            console.error('Validation failed - check your vector data format');
        } else if (error.message.includes('dimension')) {
            console.error('Vector dimension mismatch - check index configuration');
        }
        
        return {
            success: false,
            count: 0,
            message: `Batch processing failed: ${error.message}`
        };
    }
}

// Usage
const documents = [
    {
        id: 'article_001',
        title: 'Getting Started with TypeScript',
        content: 'TypeScript is a powerful superset of JavaScript...',
        author: 'Jane Developer',
        category: 'programming',
        vector: [0.1, 0.2, 0.3, 0.4]
    },
    {
        id: 'article_002',
        title: 'React Best Practices',
        content: 'When building React applications, it is important...',
        author: 'John React',
        category: 'frontend',
        vector: [0.5, 0.6, 0.7, 0.8]
    }
];

const batchResult = await processBatchDocuments(index, documents);
console.log('Batch processing result:', batchResult);

Response Format

// Standard successful upsert response
{
    "status": "success",
    "message": "Upserted 5 vectors"
}