> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cyborg.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Upsert

Adds vectors to the index, or replaces existing vectors with the same ID. `upsert()` takes either an array of items or parallel arrays:

```typescript theme={null}
async upsert({
    items?: VectorItem[],                            // Shape 1
    ids?: string[],                                  // Shape 2
    vectors?: number[][] | Float32Array,             // Shape 2
    metadata?: (Record<string, unknown> | null)[],   // Shape 2, optional
    contents?: (string | null)[],                    // Shape 2, optional
}): Promise<UpsertResponse>
```

### Parameters

#### Shape 1: items

| Parameter | Type | Default | Description |
| - | - | - | - |
| `items` | [`VectorItem[]`](../types#vectoritem) | - | One object per vector. |

Each item can contain:

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `string` | Yes | Unique identifier. |
| `vector` | `number[]` | Unless the index has an embedding model and `contents` is set | Vector data. |
| `contents` | `string` or bytes (`Uint8Array`, `Buffer`) | No | Encrypted before storage. |
| `metadata` | `object` | No | Key-value pairs for filtering. |

Strings in `contents` are stored as-is; bytes are base64-encoded first. [`get()`](./get) always returns `contents` as a `string`, so bytes come back as their base64 text.

<Tip>Store dates in `metadata` as epoch milliseconds (`date.getTime()`) so range filters work on them. See [Dates](../types#dates).</Tip>

#### Shape 2: parallel arrays

| Parameter | Type | Default | Description |
| - | - | - | - |
| `ids` | `string[]` | - | Unique identifier for each vector. |
| `vectors` | `number[][]` or `Float32Array` | - | Vector data. A `Float32Array` holds all vectors back to back and is sent in a faster binary format. |
| `metadata` | `(object \| null)[]` | `undefined` | *(Optional)* Metadata per vector, same length as `ids`. |
| `contents` | `(string \| null)[]` | `undefined` | *(Optional)* Contents per vector, same length as `ids`. |

<Warning>Don't upsert vectors containing `NaN` or infinite values. The service stores them, and later `get` or `query` calls on that index that return vectors or distances fail with a `5xx` error.</Warning>

### Returns

`Promise<UpsertResponse>` with `status` and `message`, e.g. `{ status: 'success', message: 'Upserted 2 vectors' }`. An empty `items` array returns `{ status: 'success', message: 'No items to upsert' }` without calling the service.

### Exceptions

<AccordionGroup>
  <Accordion title="CyborgDBValidationError">
    * The input matches neither shape, arrays differ in length, or an `items` or `number[][]` vector contains a non-finite number. Thrown before any request is sent. `Float32Array` input isn't checked.
    * The service rejects the items (HTTP `400`), for example a vector with the wrong dimension.
  </Accordion>

  <Accordion title="CyborgDBAuthenticationError">
    The `indexKey` or `apiKey` is invalid, or a read-only user key is used (HTTP `401`/`403`).
  </Accordion>

  <Accordion title="CyborgDBServiceError">
    The service returns `5xx`.
  </Accordion>
</AccordionGroup>

See [Errors](../errors) for the full hierarchy.

### Example Usage

#### Items

```typescript theme={null}
const result = await index.upsert({
    items: [
        { id: 'doc1', vector: [0.1, 0.2, 0.3, 0.4], contents: 'First document' },
        { id: 'doc2', vector: [0.5, 0.6, 0.7, 0.8], metadata: { category: 'news' } },
    ],
});
console.log(result);
// Output: { status: 'success', message: 'Upserted 2 vectors' }
```

#### Parallel arrays

```typescript theme={null}
await index.upsert({
    ids: ['vec1', 'vec2', 'vec3'],
    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],
    ],
    metadata: [{ category: 'news' }, { category: 'research' }, null],
    contents: ['First body', 'Second body', null],
});
```

#### Float32Array (binary)

```typescript theme={null}
const dim = 4;
const ids = ['vec4', 'vec5', 'vec6'];

// All vectors back to back: ids.length * dim values
const vectors = new Float32Array(ids.length * dim).map(() => Math.random());

await index.upsert({ ids, vectors });
```

Use a `Float32Array` when the vectors already come from a model or buffer in that form.

#### Replace an existing item

```typescript theme={null}
await index.upsert({ items: [{ id: 'doc1', vector: [0.1, 0.2, 0.3, 0.4], metadata: { version: 1 } }] });

// Same ID: replaces the vector, contents, and metadata
await index.upsert({ items: [{ id: 'doc1', vector: [0.2, 0.3, 0.4, 0.5], metadata: { version: 2 } }] });

const [item] = await index.get({ ids: ['doc1'], include: ['metadata'] });
console.log(item.metadata);
// Output: { version: 2 }
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.