> ## 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 new vectors to the index or updates existing ones. Vector data is encrypted end-to-end before being stored.

```go theme={null}
// Upsert accepts either VectorItems or BinaryUpsertParams
func (e *EncryptedIndex) Upsert(ctx context.Context, input UpsertInput) error

// Binary format upsert (convenience method)
func (e *EncryptedIndex) UpsertVectors(ctx context.Context, ids []string, vectors [][]float32, metadata []map[string]interface{}) error
```

### Parameters (Upsert)

| Parameter | Type                                            | Description                                  |
| --------- | ----------------------------------------------- | -------------------------------------------- |
| `ctx`     | `context.Context`                               | Context for cancellation/timeouts            |
| `input`   | [`UpsertInput`](../types#upsertinput-interface) | Either `VectorItems` or `BinaryUpsertParams` |

### Parameters (UpsertVectors)

| Parameter  | Type                       | Description                                  |
| ---------- | -------------------------- | -------------------------------------------- |
| `ctx`      | `context.Context`          | Context for cancellation/timeouts            |
| `ids`      | `[]string`                 | Slice of unique identifiers, one per vector  |
| `vectors`  | `[][]float32`              | Slice of vector embeddings                   |
| `metadata` | `[]map[string]interface{}` | Optional slice of metadata maps (can be nil) |

<Tip>`UpsertVectors` automatically uses an optimized binary transfer format for better performance with large batches.</Tip>

#### VectorItem

```go theme={null}
type VectorItem struct {
    Id       string                 `json:"id"`                 // Unique identifier
    Vector   []float32              `json:"vector,omitempty"`   // Vector data
    Contents internal.NullableContents `json:"contents,omitempty"` // Optional payload (see types reference)
    Metadata map[string]interface{} `json:"metadata,omitempty"` // Optional metadata
}
```

<Note>`Contents` is a generated nullable wrapper and is not directly constructible from the public package. See the [Types reference](../types#vectoritem) for the helper-based setter pattern; most Go code leaves it zero-valued.</Note>

### Returns

| Type    | Description                                       |
| ------- | ------------------------------------------------- |
| `error` | Any error encountered during the upsert operation |

### Exceptions

<AccordionGroup>
  <Accordion title="Error">
    * Throws if the API request fails due to network connectivity issues.
    * Throws if authentication fails (invalid API key).
    * Throws if the encryption key is invalid for the specified index.
    * Throws if there are internal server errors preventing the upsert.
  </Accordion>

  <Accordion title="Validation Errors">
    * Throws detailed validation errors for invalid VectorItem objects.
    * Throws if vector dimensions don't match the index configuration.
    * Throws if required fields are missing from vector items.
    * Throws if array lengths don't match in parallel array format.
    * Throws if vector elements are not finite numbers.
  </Accordion>
</AccordionGroup>

### Example Usage

```go theme={null}
package main

import (
    "context"
    "encoding/hex"
    "log"
    
    "github.com/cyborginc/cyborgdb-go"
)

func main() {
    // Load existing index
    client, _ := cyborgdb.NewClient("http://localhost:8000", "your-api-key")
    indexKeyHex := "your-64-character-hex-key-here" // 32-byte key encoded as 64 hex chars
    key, err := hex.DecodeString(indexKeyHex)
    if err != nil {
        log.Fatal(err)
    }
    index, _ := client.LoadIndex(context.Background(), "my-documents", key)
    
    // Create vector items
    items := cyborgdb.VectorItems{
        {
            Id:     "doc1",
            Vector: []float32{0.1, 0.2, 0.3, 0.4, 0.5},
        },
        {
            Id:     "doc2",
            Vector: []float32{0.6, 0.7, 0.8, 0.9, 1.0},
        },
    }
    
    // Upsert vectors
    ctx := context.Background()
    err := index.Upsert(ctx, items)
    if err != nil {
        log.Fatal("Upsert failed:", err)
    }
    
    log.Printf("Successfully upserted %d vectors", len(items))
}
```

#### Upsert with Metadata

```go theme={null}
func upsertDocuments(index *cyborgdb.EncryptedIndex) error {
    items := cyborgdb.VectorItems{
        {
            Id:     "article_123",
            Vector: []float32{0.1, 0.2, 0.3, 0.4}, // Document embedding
            Metadata: map[string]interface{}{
                "title":     "Go Programming Guide",
                "category":  "programming",
                "author":    "John Doe",
                "published": "2024-01-15",
                "tags":      []string{"golang", "tutorial", "beginner"},
            },
        },
        {
            Id:     "article_124", 
            Vector: []float32{0.5, 0.6, 0.7, 0.8},
            Metadata: map[string]interface{}{
                "title":     "Advanced Go Patterns",
                "category":  "programming", 
                "author":    "Jane Smith",
                "published": "2024-01-20",
                "tags":      []string{"golang", "advanced", "patterns"},
            },
        },
    }
    
    ctx := context.Background()
    return index.Upsert(ctx, items)
}
```

#### UpsertVectors (Binary Format)

```go theme={null}
// Efficient bulk upsert using binary transfer
ids := []string{"vec1", "vec2", "vec3"}
vectors := [][]float32{
    {0.1, 0.2, 0.3, 0.4},
    {0.5, 0.6, 0.7, 0.8},
    {0.9, 1.0, 1.1, 1.2},
}

err := index.UpsertVectors(context.Background(), ids, vectors, nil)
if err != nil {
    log.Fatal("UpsertVectors failed:", err)
}
```
