Write Records with Vectors
RushDB lets you attach pre-computed embedding vectors to records at write time, eliminating the need for a separate bulk-upsert call. Any operation that creates or modifies records accepts a vectors parameter.
This feature requires at least one external index on the target (label, propertyName). It works on RushDB Cloud and on a self-hosted engine, except inside a transaction on a self-hosted engine: the engine cannot stage inline vectors, so the SDK throws DirectModeError before sending the write. Write the vectors after the commit with upsertVectors, or outside the transaction.
vectors parameter format
| Field | Type | Required | Description |
|---|---|---|---|
propertyName | string | yes | Property name this vector is associated with |
vector | number[] | yes | Pre-computed embedding vector |
similarityFunction | string | no | Required when multiple indexes exist on the same property |
index | string | no | The index to write to, by name (or id). Overrides selection by property and shape. |
Create a Record with Vectors
Record creation and vector storage happen atomically in one request.
- Python
- TypeScript
- shell
db.records.create()
record = db.records.create(
label="Article",
data={
"title": "How transformers work",
"body": "Attention is all you need ...",
},
vectors=[
{"propertyName": "body", "vector": my_embedder.embed("Attention is all you need ...")}
],
)
print(record.id) # record created AND vector written atomically
db.records.create()
const { data: record } = await db.records.create({
label: 'Article',
data: {
title: 'How transformers work',
body: 'Attention is all you need ...'
},
vectors: [{ propertyName: 'body', vector: myEmbed('Attention is all you need ...') }]
})
console.log(record.id) // record created AND vector written atomically
POST /api/v1/records
curl -X POST https://api.rushdb.com/api/v1/records \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Article",
"data": {
"title": "How transformers work",
"body": "Attention is all you need ..."
},
"vectors": [
{ "propertyName": "body", "vector": [0.1, 0.2, 0.3] }
]
}'
Upsert with Vectors
upsert is idempotent on the record's natural key. Passing vectors writes or replaces the stored vector in the same call.
- Python
- TypeScript
- shell
db.records.upsert()
# First call — creates the record + writes vector
r1 = db.records.upsert(
label="Article",
data={"slug": "transformers-101", "title": "Transformers 101", "body": "..."},
options={"mergeBy": ["slug"], "mergeStrategy": "append"},
vectors=[{"propertyName": "body", "vector": v1}],
)
# Second call — same slug → updates data + replaces the vector
r2 = db.records.upsert(
label="Article",
data={"slug": "transformers-101", "title": "Transformers 101 (revised)", "body": "Updated ..."},
options={"mergeBy": ["slug"], "mergeStrategy": "append"},
vectors=[{"propertyName": "body", "vector": v2}],
)
# r1.id == r2.id
db.records.upsert()
// First call — creates the record + writes vector
const { data: r1 } = await db.records.upsert({
label: 'Article',
data: { slug: 'transformers-101', title: 'Transformers 101', body: '...' },
vectors: [{ propertyName: 'body', vector: v1 }]
})
// Second call — same slug → updates data + replaces the vector
const { data: r2 } = await db.records.upsert({
label: 'Article',
data: { slug: 'transformers-101', title: 'Transformers 101 (revised)', body: 'Updated ...' },
vectors: [{ propertyName: 'body', vector: v2 }]
})
console.log(r1.id === r2.id) // true — same record
POST /api/v1/records
curl -X POST https://api.rushdb.com/api/v1/records \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Article",
"data": { "slug": "transformers-101", "title": "Transformers 101", "body": "..." },
"options": { "mergeBy": ["slug"], "mergeStrategy": "append" },
"vectors": [{ "propertyName": "body", "vector": [0.1, 0.2, 0.3] }]
}'
Set with Vectors
set replaces all properties of a record. Including vectors writes those vectors at the same time.
- Python
- TypeScript
- shell
db.records.set()
db.records.set(
target=record,
label="Product",
data={"name": "Widget Pro", "price": 19.99},
vectors=[{"propertyName": "description", "vector": new_vec}],
)
db.records.set()
await db.records.set(rec.id, {
data: { name: 'Widget Pro', price: 19.99 },
vectors: [{ propertyName: 'description', vector: newVec }]
})
PUT /api/v1/records/:id
curl -X PUT https://api.rushdb.com/api/v1/records/rec_abc123 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Product",
"data": { "name": "Widget Pro", "price": 19.99 },
"vectors": [{ "propertyName": "description", "vector": [0.5, 0.6, 0.7] }]
}'
Create Multiple Records with Vectors
createMany / create_many accepts a top-level vectors array indexed by row position — each entry is a list of vector entries for that row.
For the common case of one vector per record, you can pass a flat VectorEntry[] instead of the nested VectorEntry[][] — the SDK auto-wraps it into per-row entries.
- Python
- TypeScript
- shell
db.records.create_many()
db.records.create_many(
label="Product",
data=[
{"name": "Alpha", "description": "First product"},
{"name": "Beta", "description": "Second product"},
{"name": "Gamma", "description": "Third product"},
],
vectors=[
[{"propertyName": "description", "vector": [1, 0, 0]}], # row 0
[{"propertyName": "description", "vector": [0, 1, 0]}], # row 1
[{"propertyName": "description", "vector": [0, 0, 1]}], # row 2
],
)
Sparse vectors — any rows beyond vectors length are skipped:
db.records.create_many(
label="Product",
data=[{"name": "Alpha"}, {"name": "Beta"}, {"name": "Gamma"}],
vectors=[[{"propertyName": "description", "vector": my_vec}]], # only row 0
)
Flat form — one vector per record, auto-wraps to per-row entries:
db.records.create_many(
label="Product",
data=[{"name": "Alpha"}, {"name": "Beta"}],
vectors=[{"propertyName": "description", "vector": [1, 0, 0]}], # flat list
)
db.records.createMany()
await db.records.createMany({
label: 'Product',
data: [
{ name: 'Alpha', description: 'First product' },
{ name: 'Beta', description: 'Second product' },
{ name: 'Gamma', description: 'Third product' }
],
vectors: [
[{ propertyName: 'description', vector: [1, 0, 0] }], // row 0
[{ propertyName: 'description', vector: [0, 1, 0] }], // row 1
[{ propertyName: 'description', vector: [0, 0, 1] }] // row 2
],
options: { returnResult: true }
})
Sparse vectors — any rows beyond vectors.length are skipped:
await db.records.createMany({
label: 'Product',
data: [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }],
// only row 0 gets a vector; rows 1 and 2 are skipped
vectors: [[{ propertyName: 'description', vector: myVec }]]
})
The SDK throws synchronously if vectors.length > data.length:
Error: vectors length (3) exceeds the number of data rows (2)
Flat form — one vector per record, auto-wraps to per-row entries:
await db.records.createMany({
label: 'Product',
data: [
{ name: 'Alpha', description: 'First product' },
{ name: 'Beta', description: 'Second product' }
],
vectors: [{ propertyName: 'description', vector: [1, 0, 0] }], // flat list
options: { returnResult: true }
})
POST /api/v1/records/import/json
curl -X POST https://api.rushdb.com/api/v1/records/import/json \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Product",
"data": [
{ "name": "Alpha", "description": "First product" },
{ "name": "Beta", "description": "Second product" },
{ "name": "Gamma", "description": "Third product" }
],
"vectors": [
[{ "propertyName": "description", "vector": [1, 0, 0] }],
[{ "propertyName": "description", "vector": [0, 1, 0] }],
[{ "propertyName": "description", "vector": [0, 0, 1] }]
]
}'
Import CSV with Vectors
CSV is a raw string, so per-row vectors are supplied separately. Row indices are 0-based after the header is consumed.
- Python
- TypeScript
- shell
db.records.import_csv()
csv_data = """name,description
Alpha,First product
Beta,Second product
Gamma,Third product"""
db.records.import_csv(
label="Product",
data=csv_data,
vectors=[
[{"propertyName": "description", "vector": [1, 0, 0]}], # csv row 0
[{"propertyName": "description", "vector": [0, 1, 0]}], # csv row 1
[{"propertyName": "description", "vector": [0, 0, 1]}], # csv row 2
],
)
db.records.importCsv()
const csv = `name,description
Alpha,First product
Beta,Second product
Gamma,Third product`
await db.records.importCsv({
label: 'Product',
data: csv,
vectors: [
[{ propertyName: 'description', vector: [1, 0, 0] }], // csv row 0
[{ propertyName: 'description', vector: [0, 1, 0] }], // csv row 1
[{ propertyName: 'description', vector: [0, 0, 1] }] // csv row 2
],
options: { returnResult: true }
})
POST /api/v1/records/import/csv
curl -X POST https://api.rushdb.com/api/v1/records/import/csv \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Product",
"data": "name,description\nAlpha,First product\nBeta,Second product\nGamma,Third product",
"vectors": [
[{ "propertyName": "description", "vector": [1, 0, 0] }],
[{ "propertyName": "description", "vector": [0, 1, 0] }],
[{ "propertyName": "description", "vector": [0, 0, 1] }]
]
}'
The server returns 400 Bad Request if vectors.length exceeds the number of CSV data rows.
Multiple vectors in one call
Write vectors for multiple properties or indexes in a single operation:
- Python
- TypeScript
- shell
db.records.create(
label="Document",
data={"title": "Multi-modal doc", "abstract": "...", "fullText": "..."},
vectors=[
{"propertyName": "abstract", "vector": abstract_vec},
{"propertyName": "fullText", "vector": full_text_vec},
],
)
await db.records.create({
label: 'Document',
data: { title: 'Multi-modal doc', abstract: '...', fullText: '...' },
vectors: [
{ propertyName: 'abstract', vector: abstractVec },
{ propertyName: 'fullText', vector: fullTextVec }
]
})
curl -X POST https://api.rushdb.com/api/v1/records \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Document",
"data": { "title": "Multi-modal doc", "abstract": "...", "fullText": "..." },
"vectors": [
{ "propertyName": "abstract", "vector": [0.1, 0.2, 0.3] },
{ "propertyName": "fullText", "vector": [0.4, 0.5, 0.6] }
]
}'
Disambiguation
When a (label, propertyName) has multiple external indexes (e.g. cosine and euclidean), name the target with index, or specify similarityFunction, in each vector entry to route to the correct index. Omitting it when multiple indexes match returns 422 Unprocessable Entity.
- Python
- TypeScript
- shell
db.records.create(
label="Product",
data={"name": "Widget"},
vectors=[
{"propertyName": "embedding", "vector": vec, "similarityFunction": "cosine"}
],
)
await db.records.create({
label: 'Product',
data: { name: 'Widget' },
vectors: [{ propertyName: 'embedding', vector: vec, similarityFunction: 'cosine' }]
})
curl -X POST https://api.rushdb.com/api/v1/records \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $RUSHDB_API_KEY" \
-d '{
"label": "Product",
"data": { "name": "Widget" },
"vectors": [
{ "propertyName": "embedding", "vector": [0.1, 0.9], "similarityFunction": "cosine" }
]
}'
See also
- Bring Your Own Vectors — create external indexes and bulk-upsert
- Manage Embedding Indexes — list, stats, delete indexes
- Semantic Search — search across indexed properties