Skip to Content
ExamplesCollection lifecycle & schema
Raw

Collection lifecycle and payload schema

Everything that operates on a collection as a whole: listing what exists, checking for one, reading its configuration, deleting it — plus the payload mutation calls and the optional payload schema.

export AETHERFY_API_KEY="afy_live_your_key_here"

The Aetherfy collection lifecycle methods

OperationPythonJavaScriptReturns
Createcreate_collection(collection_name, vectors_config, distance=None, description=None, regions=None)createCollection(collectionName, vectorsConfig, description?, regions?)Collection
List allget_collections()getCollections()List[Collection] / Promise<Collection[]>
Existscollection_exists(name)collectionExists(name)bool / Promise<boolean>
Read oneget_collection(name)getCollection(name)Collection
Deletedelete_collection(name)deleteCollection(name)bool / Promise<boolean>

Note the signature difference: the Aetherfy Python create_collection accepts a standalone distance argument in third position, while the JavaScript createCollection takes the description third and expects the distance inside the vectors config.

Managing Aetherfy collections in Python

Install with pip install aetherfy-vectors (Python >= 3.9). VectorConfig and DistanceMetric live in aetherfy_vectors.models and are not re-exported from the package root; Schema, FieldDefinition and AnalysisResult are.

from aetherfy_vectors import AetherfyVectorsClient from aetherfy_vectors.models import VectorConfig, DistanceMetric, Point client = AetherfyVectorsClient() # Create. created = client.create_collection( "articles", VectorConfig(size=4, distance=DistanceMetric.COSINE), description="Published articles", ) print(created.name, created.config.size, created.config.distance) # articles 4 DistanceMetric.COSINE # Exists. print(client.collection_exists("articles")) # True print(client.collection_exists("nope")) # False # Read one. info = client.get_collection("articles") print(info.name) # articles print(info.config.size) # 4 print(info.description) # Published articles # List all. for c in client.get_collections(): print(c.name, c.config.size, c.points_count) # articles 4 0 # Delete. print(client.delete_collection("articles")) # True print(client.collection_exists("articles")) # False client.close()

Reading a collection that does not exist raises an AetherfyVectorsException subclass rather than returning None. Creating one is more forgiving than it looks: re-creating an existing collection with the same configuration is idempotent and returns 200, so a script may call create unconditionally on every run. Only a create that asks for a different configuration under a name already in use fails, with 409 COLLECTION_NAME_TAKEN.

The guard below is therefore optional for the same-configuration case, and useful when the configuration may differ or you want to branch on existence:

if not client.collection_exists("articles"): client.create_collection("articles", VectorConfig(size=4, distance=DistanceMetric.COSINE))

Deletion has one precondition worth knowing before you script it: if an Aetherfy agent is using the collection, the delete is refused with 409 COLLECTION_IN_USE and both SDKs raise CollectionInUseError, whose message names the agents blocking it. “Using” means Aetherfy has observed that agent reading or writing the collection in the last 35 days — there is nothing to declare, and a collection your agent code created at runtime is protected the same way. Stop or delete the named agents, or wait for the observation to age out, then repeat the delete.

Managing Aetherfy collections in JavaScript

Install with npm install aetherfy-vectors (Node >= 20). Import everything from the package root.

import { AetherfyVectorsClient, DistanceMetric } from 'aetherfy-vectors'; const client = new AetherfyVectorsClient(); async function main() { // Create. const created = await client.createCollection( 'articles', { size: 4, distance: DistanceMetric.COSINE }, 'Published articles', ); console.log(created.name, created.config.size, created.config.distance); // articles 4 Cosine // Exists. console.log(await client.collectionExists('articles')); // true console.log(await client.collectionExists('nope')); // false // Read one. const info = await client.getCollection('articles'); console.log(info.name, info.config.size, info.description); // articles 4 Published articles // List all. for (const c of await client.getCollections()) { console.log(c.name, c.config.size, c.points_count); } // articles 4 0 // Delete. console.log(await client.deleteCollection('articles')); // true console.log(await client.collectionExists('articles')); // false client.dispose(); } main();

The Aetherfy Collection shape

Python fieldJavaScript fieldTypeNotes
namenamestring
configconfigVectorConfigsize (int) and distance
descriptiondescriptionstring, optional
points_countpoints_countnumber, optionalServer-reported point count
statusstatusoptionalReported by the server
regionsregionsoptionalPopulated only on a plan with more than one region

Region placement is plan-scoped in Aetherfy: Free and Starter collections live in a single region, and replication across more than one region begins at the plan named Performance. The regions argument on create and the regions field here are only meaningful above that line. See Regions & replication.

Mutating Aetherfy payloads without rewriting vectors

Three calls change a point’s payload while leaving its vector alone. They differ in whether they merge, replace, or remove.

CallPythonJavaScriptSemantics
Mergeset_payload(collection_name, payload, points, key=None)setPayload(collectionName, payload, points, { key? })Additive — existing keys not mentioned are kept
Replaceoverwrite_payload(collection_name, payload, points)overwritePayload(collectionName, payload, points)Full replace — keys not mentioned are dropped
Remove keysdelete_payload(collection_name, keys, points)deletePayload(collectionName, keys, points)Deletes the named keys only

Every payload mutation call is capped at 512 points per call in both SDKs. Chunk a larger update.

Payload mutation in Aetherfy with Python

from aetherfy_vectors import AetherfyVectorsClient from aetherfy_vectors.models import VectorConfig, DistanceMetric, Point client = AetherfyVectorsClient() client.create_collection("articles", VectorConfig(size=4, distance=DistanceMetric.COSINE)) client.upsert("articles", [ Point(id=1, vector=[0.1, 0.2, 0.3, 0.4], payload={"title": "Hello", "status": "draft", "author": "ada"}), ]) # Merge: adds published_at, keeps title/status/author, updates status. client.set_payload("articles", {"status": "published", "published_at": "2026-01-01"}, [1]) print(client.retrieve("articles", [1])[0]["payload"]) # {'title': 'Hello', 'status': 'published', 'author': 'ada', 'published_at': '2026-01-01'} # Remove specific keys. client.delete_payload("articles", ["published_at"], [1]) print(client.retrieve("articles", [1])[0]["payload"]) # {'title': 'Hello', 'status': 'published', 'author': 'ada'} # Replace: everything not listed is gone. client.overwrite_payload("articles", {"title": "Hello"}, [1]) print(client.retrieve("articles", [1])[0]["payload"]) # {'title': 'Hello'} # Chunk anything larger than 512 points. ids = list(range(2000)) for start in range(0, len(ids), 512): client.set_payload("articles", {"batch": "import-7"}, ids[start:start + 512]) client.close()

Payload mutation in Aetherfy with JavaScript

import { AetherfyVectorsClient, DistanceMetric } from 'aetherfy-vectors'; const client = new AetherfyVectorsClient(); async function main() { await client.createCollection('articles', { size: 4, distance: DistanceMetric.COSINE }); await client.upsert('articles', [ { id: 1, vector: [0.1, 0.2, 0.3, 0.4], payload: { title: 'Hello', status: 'draft', author: 'ada' } }, ]); // Merge. await client.setPayload('articles', { status: 'published', published_at: '2026-01-01' }, [1]); console.log((await client.retrieve('articles', [1]))[0].payload); // { title: 'Hello', status: 'published', author: 'ada', published_at: '2026-01-01' } // Remove keys. await client.deletePayload('articles', ['published_at'], [1]); console.log((await client.retrieve('articles', [1]))[0].payload); // { title: 'Hello', status: 'published', author: 'ada' } // Replace. await client.overwritePayload('articles', { title: 'Hello' }, [1]); console.log((await client.retrieve('articles', [1]))[0].payload); // { title: 'Hello' } // Chunk anything larger than 512 points. const ids = Array.from({ length: 2000 }, (_, i) => i); for (let start = 0; start < ids.length; start += 512) { await client.setPayload('articles', { batch: 'import-7' }, ids.slice(start, start + 512)); } client.dispose(); } main();

The Aetherfy payload schema

A collection can carry an optional schema describing the shape of its payloads. The schema is a set of named field definitions, and an enforcement mode decides what happens when a write does not match.

Enforcement modeBehaviour
offThe schema is stored but not applied. This is the default.
warnMismatches are surfaced but the write proceeds.
strictMismatches reject the write.

Field definition fields:

Python (FieldDefinition)JavaScript (FieldDefinition)Meaning
typetypeOne of null, boolean, string, integer, float, array, object
requiredrequiredWhether the key must be present
element_typeelementTypeElement type, for array fields
fieldsfieldsNested field definitions, for object fields

Note the casing split again: Python uses element_type, JavaScript uses elementType.

Setting and reading an Aetherfy schema in Python

Schema, FieldDefinition and AnalysisResult are exported from the aetherfy_vectors package root.

from aetherfy_vectors import AetherfyVectorsClient, Schema, FieldDefinition from aetherfy_vectors.models import VectorConfig, DistanceMetric, Point client = AetherfyVectorsClient() client.create_collection("articles", VectorConfig(size=4, distance=DistanceMetric.COSINE)) schema = Schema( fields={ "title": FieldDefinition(type="string", required=True), "status": FieldDefinition(type="string", required=True), "views": FieldDefinition(type="integer", required=False), "tags": FieldDefinition(type="array", required=False, element_type="string"), }, description="Article payload contract", ) etag = client.set_schema("articles", schema, enforcement="strict", description="v1") print(etag) # the ETag string of the new schema version # Read it back. Returns None when no schema is set. loaded = client.get_schema("articles") print(sorted(loaded.fields)) # ['status', 'tags', 'title', 'views'] print(loaded.fields["title"].type) # string print(loaded.fields["title"].required) # True print(loaded.fields["tags"].element_type) # string # Remove the schema. print(client.delete_schema("articles")) # True print(client.get_schema("articles")) # None client.close()

set_schema returns the new schema’s ETag as a string, not a schema object. get_schema returns Optional[Schema] — None means the collection exists but has no schema defined, which is a normal state and not an error.

The enforcement argument accepts only "off", "warn" or "strict"; anything else raises before a request is made.

Setting and reading an Aetherfy schema in JavaScript

import { AetherfyVectorsClient, DistanceMetric, Schema, } from 'aetherfy-vectors'; const client = new AetherfyVectorsClient(); async function main() { await client.createCollection('articles', { size: 4, distance: DistanceMetric.COSINE }); const schema: Schema = { fields: { title: { type: 'string', required: true }, status: { type: 'string', required: true }, views: { type: 'integer', required: false }, tags: { type: 'array', required: false, elementType: 'string' }, }, description: 'Article payload contract', }; const etag = await client.setSchema('articles', schema, 'strict', 'v1'); console.log(etag); // the ETag string of the new schema version const loaded = await client.getSchema('articles'); if (loaded) { console.log(Object.keys(loaded.fields).sort()); // [ 'status', 'tags', 'title', 'views' ] console.log(loaded.fields.title.type); // string console.log(loaded.fields.title.required); // true console.log(loaded.fields.tags.elementType); // string } console.log(await client.deleteSchema('articles')); // true console.log(await client.getSchema('articles')); // null client.dispose(); } main();

getSchema resolves to Schema | null; null means no schema is defined. The enforcement mode is the third positional argument and defaults to 'off'.

Inferring an Aetherfy schema from existing points

analyze_schema / analyzeSchema samples the points already in a collection and proposes a schema. It writes nothing — you decide whether to install the suggestion.

sample_size must be between 100 and 10000 inclusive; the default is 1000.

Analyzing in Python

from aetherfy_vectors import AetherfyVectorsClient client = AetherfyVectorsClient() result = client.analyze_schema("articles", sample_size=1000) print(result.collection) # articles print(result.sample_size) # number of points actually sampled print(result.total_points) # points in the collection print(result.processing_time_ms) # server-side processing time, integer ms print(sorted(result.suggested_schema.fields)) # ['status', 'tags', 'title', 'views'] # Install the suggestion, still without enforcing it. etag = client.set_schema("articles", result.suggested_schema, enforcement="off") client.close()

Analyzing in JavaScript

import { AetherfyVectorsClient } from 'aetherfy-vectors'; const client = new AetherfyVectorsClient(); async function main() { const result = await client.analyzeSchema('articles', 1000); console.log(result.collection); // articles console.log(result.sampleSize); // number of points actually sampled console.log(result.totalPoints); // points in the collection console.log(result.processingTimeMs); // server-side processing time, integer ms console.log(Object.keys(result.suggestedSchema.fields).sort()); // [ 'status', 'tags', 'title', 'views' ] await client.setSchema('articles', result.suggestedSchema, 'off'); client.dispose(); } main();

The Aetherfy AnalysisResult shape

Python fieldJavaScript fieldType
collectioncollectionstring
sample_sizesampleSizeinteger
total_pointstotalPointsinteger
fieldsfieldsmap of field name to per-field analysis
suggested_schemasuggestedSchemaSchema
processing_time_msprocessingTimeMsinteger milliseconds

A safe rollout is: analyze_schema to get a suggestion, set_schema with off to record it, switch to warn while you watch for mismatches, then strict once writes are clean.

Enforcement only ever applies to new writes, so switching to strict says nothing about the points you already have. Before you switch, POST /api/v1/schema/{collection}/conformance scans the stored points against the stored schema and tells you how many would fail, which fields are responsible, and a capped sample of the offending point ids. It is read-only and repairs nothing. That turns “watch for mismatches” into a number you can read before the switch rather than after it.

Related: First collection for creating and filling a collection, Retrieve, delete, count for removing points rather than the whole collection, and the SDK reference for the complete method list.

Last updated on