Migrate from v2 to v3
The Weaviate TypeScript client supports TypeScript and JavaScript.
The v3 client supports server side development (Node.js hosted). See v3 packages for details. If your application is browser based, consider using the TypeScript client v2.
Install
To install the TypeScript client v3, follow these steps:
Update Node.js
The v3 client requires
Node v18
or higher.Install the new client package
npm install weaviate-client
Upgrade Weaviate
The v3 client requires Weaviate core
1.23.7
or higher. Whenever possible, use the latest versions of Weaviate core and the Weaviate client.Open a gRPC port
The default gRPC port is 50051.
docker-compose.yml
To map the Weaviate gRPC port in your Docker container to a local port, add this code to your
docker-compose.yml
file:ports:
- 8080:8080
- 50051:50051
Instantiate a client
The weaviate object is the main entry point for all API operations. The v3 client instantiates the weaviate object and creates a connection to your Weaviate instance.
In most cases, you should use one of the connection helper functions to connect to your Weaviate instance:
connectToWCD
connectToLocal
connectToCustom
You can also use a custom configuration to instantiate the client directly:
- Local
- Weaviate Cloud
- Custom
import weaviate from 'weaviate-client'
const client = await weaviate.connectToLocal()
console.log(client)
import weaviate from 'weaviate-client'
const client = await weaviate.connectToWeaviateCloud(
'WEAVIATE_INSTANCE_URL', { // Replace WEAVIATE_INSTANCE_URL with your instance URL
authCredentials: new weaviate.ApiKey('WEAVIATE_INSTANCE_API_KEY'),
headers: {
'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY || '', // Replace with your inference API key
}
}
)
console.log(client)
import weaviate from 'weaviate-client'
const client = await weaviate.connectToCustom({
httpHost: 'localhost',
httpPort: 8080,
grpcHost: 'localhost',
grpcPort: 50051,
grpcSecure: true,
httpSecure: true,
authCredentials: new weaviate.ApiKey('WEAVIATE_INSTANCE_API_KEY'),
headers: {
'X-Cohere-Api-Key': process.env.COHERE_API_KEY || '' // Replace with your inference API key
}
})
console.log(client)
Changes in v3
The v3 client introduces a new way to work with your data. Here are some of the important changes:
- Collection object replaces client object
- Builder pattern is removed
- Batch Inserts
- Close clients explicitly
- Data filtering
- Namespace for generative models
- Update return object
Work with collections
The v2 client uses the client
object for CRUD and search operations. In the v3 client, the collection
object replaces the client
object.
After you create a connection, you do not have to specify the collection for each operation. This helps to reduce errors.
- Client v3
- Client v2
const myCollection = client.collections.get('JeopardyQuestion');
const result = await myCollection.query.fetchObjects()
console.log(JSON.stringify(result.objects, null, 2));
result = await client
.graphql
.get()
.withClassName('JeopardyQuestion')
.withFields('question')
.do();
console.log(JSON.stringify(result, null, 2));
The collection object can be re-used throughout the codebase.
Builder Pattern is removed
The v2 client uses builder patterns to construct queries. Builder patterns can be confusing and can lead to invalid queries.
The v3 client doesn't use the builder pattern. The v3 client uses specific methods and method parameters instead.
- Client v3
- Client v2
let result
const myCollection = client.collections.get('JeopardyQuestion');
result = await myCollection.query.nearText(['animals in movies'],{
limit: 2,
returnProperties: ['question', 'answer'],
returnMetadata: ['distance']
})
console.log(JSON.stringify(result.objects, null, 2));
let result;
result = await client.graphql
.get()
.withClassName('JeopardyQuestion')
.withNearText({ concepts: ['animals in movies'] })
.withLimit(2)
.withFields('question answer _additional { distance }')
.do();
console.log(JSON.stringify(result, null, 2));
Batch Inserts
The insertMany()
method replaces objectBatcher()
to make batch insertions easier.
For more information on batch processing, see Batch Inserts.
- Client v3
- Client v2
const questions = client.collections.get("CollectionName")
const dataObject = [...]; // your data
await questions.data.insertMany(dataBatch);
let className = 'CollectionName'; // Replace with your collection name
let dataObject = [...];
let batcher5 = client.batch.objectsBatcher();
for (const dataObj of dataObject)
batcher5 = batcher5.withObject({
class: className,
properties: dataObj,
});
// Flush
await batcher5.do();
Client Close Method
The client uses a keep-alive header to maintain long-lived connections to Weaviate.
After you establish the connection to your Weaviate instance, subsequent calls are faster. When you finish your client operations, close the connection to free server resources.
Use the client.close()
method to close the connection instead of waiting for the connection to time out.
Filter data
The Filter
helper class makes it easier to use filters with conditions. The v3 client streamlines how you use Filter
so your code is cleaner and more concise.
- Client v3
- Client v2
import weaviate, { Filters } from 'weaviate-client';
const myCollection = client.collections.get('JeopardyQuestion');
const result = await myCollection.query.fetchObjects({
returnProperties: ['question', 'answer','round', 'points'],
filters: Filters.and(
myCollection.filter.byProperty('round').equal('Double Jeopardy!'),
myCollection.filter.byProperty('points').lessThan(600)
),
limit: 3,
})
console.log(JSON.stringify(result, null, 2));
result = await client.graphql
.get()
.withClassName('JeopardyQuestion')
.withWhere({
operator: 'And',
operands: [
{
path: ['round'],
operator: 'Equal',
valueText: 'Double Jeopardy!',
},
{
path: ['points'],
operator: 'LessThan',
valueInt: 600,
},
],
})
.withLimit(3)
.withFields('question answer round points')
.do();
console.log(JSON.stringify(result, null, 2));
Generate Namespace
The v3 client adds a new namespace, generate
for generative queries. This makes it easier to distinguish between generative queries and vector searches.
- Client v3
- Client v2
const generatePrompt = `Convert this quiz question: {question} and answer: {answer} into a trivia tweet.`;
const myCollection = client.collections.get('JeopardyQuestion');
const result = await myCollection.generate.nearText(['World history'],{
singlePrompt: generatePrompt,
},{
limit: 2,
returnProperties: ['round'],
})
console.log(JSON.stringify(result.objects, null, 2));
let result;
generatePrompt = 'Convert this quiz question: {question} and answer: {answer} into a trivia tweet.';
result = await client.graphql
.get()
.withClassName('JeopardyQuestion')
.withGenerate({
singlePrompt: generatePrompt,
})
.withNearText({
concepts: ['World history'],
})
.withFields('round')
.withLimit(2)
.do();
console.log(JSON.stringify(result, null, 2));
Return object
The new client has a cleaner return object. It is easier to access important information like object UUIDs, object metadata, and generative query results.
- Client v3
- Client v2
response.objects[0].properties.title // Get the `title` property of the first object
response.objects[0].uuid // Get the ID of the first object
response.objects[0].generated // Get the generated text from a `singlePrompt` request
response.generated // Get the generated text from a `groupedTask` request
response.metadata?.creationTime // Get the creation time as a native JS Date value
response.data?.Get?.Article?.[0].title // Get the `title` property of the first object
response.data?.Get?.Article?.[0]['_additional']?.id // Get the ID of the first object
response.data?.Get?.Article?.[0]['_additional']?.generate?.singleResult // Get the generated text from a `singlePrompt` request
response.data?.Get?.Article?.[0]['_additional']?.generate.groupedResult // Get the generated text from a `groupedTask` request
response.data?.Get?.Article?.[0]['_additional']?.creationTimeUnix // Get the timestamp when the object was created
Code comparison
These samples compare v2 client code and v3 client code.
The comparison samples omit sections of the code that are the same for both clients. The complete v2 and v3 client scripts are here.
Imports
- Client v3
- Client v2
import weaviate from 'weaviate-client';
import 'dotenv/config';
import weaviate, { ApiKey, WeaviateClient } from 'weaviate-ts-client';
import 'dotenv/config'
Connect to Weaviate Cloud
- Client v3
- Client v2
// connect to your Weaviate instance on WCD
const client = await weaviate.connectToWeaviateCloud(
process.env.WEAVIATE_URL || '',
{
authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY || ''),
headers: {
'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY || '',
}
}
)
// connect to your Weaviate instance on WCD
const client: WeaviateClient = weaviate.client({
scheme: process.env.WEAVIATE_SCHEME_URL || '',
host: process.env.WEAVIATE_URL || '',
apiKey: new ApiKey(process.env.WEAVIATE_API_KEY || ''),
headers: { 'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY || '' },
});
Create a collection
- Client v3
- Client v2
// create a new collection
await client.collections.create({
name: collectionName,
vectorizers: weaviate.configure.vectorizer.text2VecOpenAI(),
})
const schemaDefinition = {
class: collectionName,
vectorizer: 'text2vec-openai',
}
// create a new collection
await client.schema.classCreator().withClass(schemaDefinition).do()
Batch insert
- Client v3
- Client v2
// define a collection to interact with
const myCollection = client.collections.get(collectionName)
// bulk insert data to your collection
await myCollection.data.insertMany(await response.json())
let counter = 0;
let batcher = client.batch.objectsBatcher();
// bulk insert data to your collection
for (const dataObjects of data) {
batcher = batcher.withObject({
class: collectionName,
properties: dataObjects,
});
// push a batch of 10 objects
if (++counter > 9) {
await batcher.do();
batcher = client.batch.objectsBatcher();
counter = 0;
}
}
// push the remaining batch of objects
if (counter > 0) {
await batcher.do();
}
Query your data
- Client v3
- Client v2
// run a nearText search; limit 2 results; show distance metrics
const queryResponse = await myCollection.query.nearText('songs about cowboys',{
limit: 2,
returnMetadata: ['distance']
})
console.log('Here are songs about cowboys: ', queryResponse.objects)
// run a nearText search; limit 2 results; show distance metrics
const queryResponse = await client
.graphql
.get()
.withClassName(collectionName) // define a collection to interact with
.withFields("title artist _additional { distance id }")
.withNearText({
"concepts": ['songs about cowboys']
})
.withLimit(2)
.do();
console.log('Here are songs about cowboys:', queryResponse.data.Get.RollingStones)
Delete a collection
- Client v3
- Client v2
// delete your collection
await client.collections.delete(collectionName)
console.log('Collection Exists:', await client.collections.exists(collectionName))
}
// delete your collection
await client.schema.classDeleter().withClassName(collectionName).do();
console.log('Collection Exists:', await client.schema.exists(collectionName))
}
Sample scripts
These scripts are complete versions of the client comparison code from this section.
- Client v3
- Client v2
import weaviate from 'weaviate-client';
import 'dotenv/config';
async function main() {
// define a collection name
const collectionName = 'RollingStones'
// connect to your Weaviate instance on WCD
const client = await weaviate.connectToWeaviateCloud(
process.env.WEAVIATE_URL || '',
{
authCredentials: new weaviate.ApiKey(process.env.WEAVIATE_API_KEY || ''),
headers: {
'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY || '',
}
}
)
// create a new collection
await client.collections.create({
name: collectionName,
vectorizers: weaviate.configure.vectorizer.text2VecOpenAI(),
})
const response = await fetch('https://raw.githubusercontent.com/weaviate/weaviate-io/tsdocs/content-fixes/_includes/clients/songs.json')
// define a collection to interact with
const myCollection = client.collections.get(collectionName)
// bulk insert data to your collection
await myCollection.data.insertMany(await response.json())
// run a nearText search; limit 2 results; show distance metrics
const queryResponse = await myCollection.query.nearText('songs about cowboys',{
limit: 2,
returnMetadata: ['distance']
})
console.log('Here are songs about cowboys: ', queryResponse.objects)
// delete your collection
await client.collections.delete(collectionName)
console.log('Collection Exists:', await client.collections.exists(collectionName))
}
main()
import weaviate, { ApiKey, WeaviateClient } from 'weaviate-ts-client';
import 'dotenv/config'
async function main() {
// define a collection name
const collectionName = 'RollingStones'
// connect to your Weaviate instance on WCD
const client: WeaviateClient = weaviate.client({
scheme: process.env.WEAVIATE_SCHEME_URL || '',
host: process.env.WEAVIATE_URL || '',
apiKey: new ApiKey(process.env.WEAVIATE_API_KEY || ''),
headers: { 'X-OpenAI-Api-Key': process.env.OPENAI_API_KEY || '' },
});
const schemaDefinition = {
class: collectionName,
vectorizer: 'text2vec-openai',
}
// create a new collection
await client.schema.classCreator().withClass(schemaDefinition).do()
const response = await fetch('https://raw.githubusercontent.com/weaviate/weaviate-io/tsdocs/content-fixes/_includes/clients/songs.json')
const data = await response.json()
let counter = 0;
let batcher = client.batch.objectsBatcher();
// bulk insert data to your collection
for (const dataObjects of data) {
batcher = batcher.withObject({
class: collectionName,
properties: dataObjects,
});
// push a batch of 10 objects
if (++counter > 9) {
await batcher.do();
batcher = client.batch.objectsBatcher();
counter = 0;
}
}
// push the remaining batch of objects
if (counter > 0) {
await batcher.do();
}
// run a nearText search; limit 2 results; show distance metrics
const queryResponse = await client
.graphql
.get()
.withClassName(collectionName) // define a collection to interact with
.withFields("title artist _additional { distance id }")
.withNearText({
"concepts": ['songs about cowboys']
})
.withLimit(2)
.do();
console.log('Here are songs about cowboys:', queryResponse.data.Get.RollingStones)
// delete your collection
await client.schema.classDeleter().withClassName(collectionName).do();
console.log('Collection Exists:', await client.schema.exists(collectionName))
}
main()
For more code examples, see the following:
How to migrate your code
To update v2 client code to v3, follow these steps:
- Install the v3 client package.
- Edit your v2 code to import the v3 client package.
- Edit your v2 client instantiation code.
- Edit your code to reflect the collection first client orientation.
Continue to update the v2 code until all of the old code is replace with the v3 equivalent.
Client change logs
The client change logs for each release are available on GitHub.
Questions and feedback
If you have any questions or feedback, let us know in the user forum.