!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}(),document.documentElement.setAttribute("data-announcement-bar-initially-dismissed",function(){try{return"true"===localStorage.getItem("docusaurus.announcement.dismiss")}catch(t){}return!1}())

[Skip to main content](#__docusaurus_skipToContent_fallback)

LangChain v0.2 is coming soon! Preview the new docs [here](/v0.2/docs/introduction/).

[

![🦜️🔗 Langchain](/v0.1/img/brand/wordmark.png)![🦜️🔗 Langchain](/v0.1/img/brand/wordmark-dark.png)

](/v0.1/)[Docs](/v0.1/docs/get_started/introduction/)[Use cases](/v0.1/docs/use_cases/)[Integrations](/v0.1/docs/integrations/platforms/)[API Reference](https://api.js.langchain.com)

[More](#)

*   [People](/v0.1/docs/people/)
*   [Community](/v0.1/docs/community/)
*   [Tutorials](/v0.1/docs/additional_resources/tutorials/)
*   [Contributing](/v0.1/docs/contributing/)

[v0.1](#)

*   [v0.2](https://js.langchain.com/v0.2/docs/introduction)
*   [v0.1](/v0.1/docs/get_started/introduction/)

[🦜🔗](#)

*   [LangSmith](https://smith.langchain.com)
*   [LangSmith Docs](https://docs.smith.langchain.com)
*   [LangChain Hub](https://smith.langchain.com/hub)
*   [LangServe](https://github.com/langchain-ai/langserve)
*   [Python Docs](https://python.langchain.com/)

[Chat](https://chatjs.langchain.com)[](https://github.com/langchain-ai/langchainjs)

Search

*   [Get started](/v0.1/docs/get_started/)
    
    *   [Introduction](/v0.1/docs/get_started/introduction/)
    *   [Installation](/v0.1/docs/get_started/installation/)
    *   [Quickstart](/v0.1/docs/get_started/quickstart/)
*   [LangChain Expression Language](/v0.1/docs/expression_language/)
    
    *   [Get started](/v0.1/docs/expression_language/get_started/)
    *   [Why use LCEL?](/v0.1/docs/expression_language/why/)
    *   [Interface](/v0.1/docs/expression_language/interface/)
    *   [Streaming](/v0.1/docs/expression_language/streaming/)
    *   [How to](/v0.1/docs/expression_language/how_to/routing/)
        
    *   [Cookbook](/v0.1/docs/expression_language/cookbook/)
        
    *   [LangChain Expression Language (LCEL)](/v0.1/docs/expression_language/)
*   [Modules](/v0.1/docs/modules/)
    
    *   [Model I/O](/v0.1/docs/modules/model_io/)
        
    *   [Retrieval](/v0.1/docs/modules/data_connection/)
        
        *   [Document loaders](/v0.1/docs/modules/data_connection/document_loaders/)
            
        *   [Text Splitters](/v0.1/docs/modules/data_connection/document_transformers/)
            
        *   [Retrievers](/v0.1/docs/modules/data_connection/retrievers/)
            
        *   [Retrieval](/v0.1/docs/modules/data_connection/)
        *   [Text embedding models](/v0.1/docs/modules/data_connection/text_embedding/)
            
        *   [Vector stores](/v0.1/docs/modules/data_connection/vectorstores/)
            
            *   [Custom vectorstores](/v0.1/docs/modules/data_connection/vectorstores/custom/)
        *   [Indexing](/v0.1/docs/modules/data_connection/indexing/)
        *   [Experimental](/v0.1/docs/modules/data_connection/experimental/multimodal_embeddings/google_vertex_ai/)
            
    *   [Chains](/v0.1/docs/modules/chains/)
    *   [Agents](/v0.1/docs/modules/agents/)
        
    *   [More](/v0.1/docs/modules/memory/)
        
*   [Security](/v0.1/docs/security/)
*   [Guides](/v0.1/docs/guides/)
    
*   [Ecosystem](/v0.1/docs/ecosystem/)
    
*   [LangGraph](/v0.1/docs/langgraph/)
*   * * *
    

*   [](/v0.1/)
*   [Modules](/v0.1/docs/modules/)
*   [Retrieval](/v0.1/docs/modules/data_connection/)
*   [Vector stores](/v0.1/docs/modules/data_connection/vectorstores/)
*   Custom vectorstores

Custom vectorstores
===================

If you want to interact with a vectorstore that is not already present as an [integration](/v0.1/docs/integrations/vectorstores/), you can extend the [`VectorStore` class](https://api.js.langchain.com/classes/langchain_core_vectorstores.VectorStore.html).

This involves overriding a few methods:

*   `FilterType`, if your vectorstore supports filtering by metadata, you should declare the type of the filter required.
*   `addDocuments`, which embeds and adds LangChain documents to storage. This is a convenience method that should generally use the `embeddings` passed into the constructor to embed the document content, then call `addVectors`.
*   `addVectors`, which is responsible for saving embedded vectors, document content, and metadata to the backing store.
*   `similaritySearchVectorWithScore`, which searches for vectors within the store by similarity to an input vector, and returns a tuple of the most relevant documents and a score.
*   `_vectorstoreType`, which returns an identifying string for the class. Used for tracing and type-checking.
*   `fromTexts` and `fromDocuments`, which are convenience static methods for initializing a vectorstore from data.

There are a few optional methods too:

*   `delete`, which deletes vectors and their associated metadata from the backing store based on arbitrary parameters.
*   `maxMarginalRelevanceSearch`, an alternative search mode that increases the number of retrieved vectors, reranks them to optimize for diversity, then returns top results. This can help reduce the amount of redundancy in returned results.

A few notes:

*   Different databases provide varying levels of support for storing raw content/extra metadata fields. Some higher level retrieval abstractions like [multi-vector retrieval](/v0.1/docs/modules/data_connection/retrievers/multi-vector-retriever/) in LangChain rely on the ability to set arbitrary metadata on stored vectors.
*   Generally, search type arguments that are not used directly to filter returned vectors by associated metadata should be passed into the constructor.

Here is an example of an in-memory vectorstore with no persistence that uses cosine distance:

    import { VectorStore } from "@langchain/core/vectorstores";import type { EmbeddingsInterface } from "@langchain/core/embeddings";import { Document } from "@langchain/core/documents";import { similarity as ml_distance_similarity } from "ml-distance";interface InMemoryVector {  content: string;  embedding: number[];  metadata: Record<string, any>;}export interface CustomVectorStoreArgs {}export class CustomVectorStore extends VectorStore {  declare FilterType: (doc: Document) => boolean;  memoryVectors: InMemoryVector[] = [];  _vectorstoreType(): string {    return "custom";  }  constructor(    embeddings: EmbeddingsInterface,    fields: CustomVectorStoreArgs = {}  ) {    super(embeddings, fields);  }  async addDocuments(documents: Document[]): Promise<void> {    const texts = documents.map(({ pageContent }) => pageContent);    return this.addVectors(      await this.embeddings.embedDocuments(texts),      documents    );  }  async addVectors(vectors: number[][], documents: Document[]): Promise<void> {    const memoryVectors = vectors.map((embedding, idx) => ({      content: documents[idx].pageContent,      embedding,      metadata: documents[idx].metadata,    }));    this.memoryVectors = this.memoryVectors.concat(memoryVectors);  }  async similaritySearchVectorWithScore(    query: number[],    k: number,    filter?: this["FilterType"]  ): Promise<[Document, number][]> {    const filterFunction = (memoryVector: InMemoryVector) => {      if (!filter) {        return true;      }      const doc = new Document({        metadata: memoryVector.metadata,        pageContent: memoryVector.content,      });      return filter(doc);    };    const filteredMemoryVectors = this.memoryVectors.filter(filterFunction);    const searches = filteredMemoryVectors      .map((vector, index) => ({        similarity: ml_distance_similarity.cosine(query, vector.embedding),        index,      }))      .sort((a, b) => (a.similarity > b.similarity ? -1 : 0))      .slice(0, k);    const result: [Document, number][] = searches.map((search) => [      new Document({        metadata: filteredMemoryVectors[search.index].metadata,        pageContent: filteredMemoryVectors[search.index].content,      }),      search.similarity,    ]);    return result;  }  static async fromTexts(    texts: string[],    metadatas: object[] | object,    embeddings: EmbeddingsInterface,    dbConfig?: CustomVectorStoreArgs  ): Promise<CustomVectorStore> {    const docs: Document[] = [];    for (let i = 0; i < texts.length; i += 1) {      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;      const newDoc = new Document({        pageContent: texts[i],        metadata,      });      docs.push(newDoc);    }    return this.fromDocuments(docs, embeddings, dbConfig);  }  static async fromDocuments(    docs: Document[],    embeddings: EmbeddingsInterface,    dbConfig?: CustomVectorStoreArgs  ): Promise<CustomVectorStore> {    const instance = new this(embeddings, dbConfig);    await instance.addDocuments(docs);    return instance;  }}

Then, we can call this vectorstore directly:

    import { OpenAIEmbeddings } from "@langchain/openai";import { Document } from "@langchain/core/documents";const vectorstore = new CustomVectorStore(new OpenAIEmbeddings());await vectorstore.addDocuments([  new Document({    pageContent: "Mitochondria is the powerhouse of the cell",    metadata: { id: 1 },  }),  new Document({    pageContent: "Buildings are made of brick",    metadata: { id: 2 },  }),]);await vectorstore.similaritySearch("What is the powerhouse of the cell?");

    [  Document {    pageContent: "Mitochondria is the powerhouse of the cell",    metadata: { id: 1 }  },  Document {    pageContent: "Buildings are made of brick",    metadata: { id: 2 }  }]

Or, we can interact with the vectorstore as a retriever:

    const retriever = vectorstore.asRetriever();await retriever.invoke("What is the powerhouse of the cell?");

    [  Document {    pageContent: "Mitochondria is the powerhouse of the cell",    metadata: { id: 1 }  },  Document {    pageContent: "Buildings are made of brick",    metadata: { id: 2 }  }]

* * *

#### Help us out by providing feedback on this documentation page:

[

Previous

Vector stores

](/v0.1/docs/modules/data_connection/vectorstores/)[

Next

Indexing

](/v0.1/docs/modules/data_connection/indexing/)

Community

*   [Discord](https://discord.gg/cU2adEyC7w)
*   [Twitter](https://twitter.com/LangChainAI)

GitHub

*   [Python](https://github.com/langchain-ai/langchain)
*   [JS/TS](https://github.com/langchain-ai/langchainjs)

More

*   [Homepage](https://langchain.com)
*   [Blog](https://blog.langchain.dev)

Copyright © 2024 LangChain, Inc.