diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/VectorStoreMongoDBAtlas.node.ts b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/VectorStoreMongoDBAtlas.node.ts
new file mode 100644
index 0000000000..0918a08977
--- /dev/null
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/VectorStoreMongoDBAtlas.node.ts
@@ -0,0 +1,266 @@
+import { MongoDBAtlasVectorSearch } from '@langchain/mongodb';
+import { MongoClient } from 'mongodb';
+import { type ILoadOptionsFunctions, NodeOperationError, type INodeProperties } from 'n8n-workflow';
+
+import { metadataFilterField } from '@utils/sharedFields';
+
+import { createVectorStoreNode } from '../shared/createVectorStoreNode/createVectorStoreNode';
+
+const mongoCollectionRLC: INodeProperties = {
+ displayName: 'MongoDB Collection',
+ name: 'mongoCollection',
+ type: 'resourceLocator',
+ default: { mode: 'list', value: '' },
+ required: true,
+ modes: [
+ {
+ displayName: 'From List',
+ name: 'list',
+ type: 'list',
+ typeOptions: {
+ searchListMethod: 'mongoCollectionSearch', // Method to fetch collections
+ },
+ },
+ {
+ displayName: 'Name',
+ name: 'name',
+ type: 'string',
+ placeholder: 'e.g. my_collection',
+ },
+ ],
+};
+
+const vectorIndexName: INodeProperties = {
+ displayName: 'Vector Index Name',
+ name: 'vectorIndexName',
+ type: 'string',
+ default: '',
+ description: 'The name of the vector index',
+ required: true,
+};
+
+const embeddingField: INodeProperties = {
+ displayName: 'Embedding',
+ name: 'embedding',
+ type: 'string',
+ default: 'embedding',
+ description: 'The field with the embedding array',
+ required: true,
+};
+
+const metadataField: INodeProperties = {
+ displayName: 'Metadata Field',
+ name: 'metadata_field',
+ type: 'string',
+ default: 'text',
+ description: 'The text field of the raw data',
+ required: true,
+};
+
+const sharedFields: INodeProperties[] = [
+ mongoCollectionRLC,
+ embeddingField,
+ metadataField,
+ vectorIndexName,
+];
+
+const mongoNamespaceField: INodeProperties = {
+ displayName: 'Namespace',
+ name: 'namespace',
+ type: 'string',
+ description: 'Logical partition for documents. Uses metadata.namespace field for filtering.',
+ default: '',
+};
+
+const retrieveFields: INodeProperties[] = [
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Option',
+ default: {},
+ options: [mongoNamespaceField, metadataFilterField],
+ },
+];
+
+const insertFields: INodeProperties[] = [
+ {
+ displayName: 'Options',
+ name: 'options',
+ type: 'collection',
+ placeholder: 'Add Option',
+ default: {},
+ options: [
+ {
+ displayName: 'Clear Namespace',
+ name: 'clearNamespace',
+ type: 'boolean',
+ default: false,
+ description: 'Whether to clear documents in the namespace before inserting new data',
+ },
+ mongoNamespaceField,
+ ],
+ },
+];
+
+let mongoClient: MongoClient | null = null;
+
+async function getMongoClient(context: any) {
+ if (!mongoClient) {
+ const credentials = await context.getCredentials('mongoDb');
+ mongoClient = new MongoClient(credentials.connectionString as string, {
+ appName: 'devrel.integration.n8n_vector_integ',
+ });
+ await mongoClient.connect();
+ }
+ return mongoClient;
+}
+
+async function mongoClientAndDatabase(context: any) {
+ const client = await getMongoClient(context);
+ const credentials = await context.getCredentials('mongoDb');
+ const db = client.db(credentials.database as string);
+ return { client, db };
+}
+
+async function mongoCollectionSearch(this: ILoadOptionsFunctions) {
+ const { db } = await mongoClientAndDatabase(this);
+ try {
+ const collections = await db.listCollections().toArray();
+ const results = collections.map((collection) => ({
+ name: collection.name,
+ value: collection.name,
+ }));
+
+ return { results };
+ } catch (error) {
+ throw new NodeOperationError(this.getNode(), `Error: ${error.message}`);
+ }
+}
+export class VectorStoreMongoDBAtlas extends createVectorStoreNode({
+ meta: {
+ displayName: 'MongoDB Atlas Vector Store',
+ name: 'vectorStoreMongoDBAtlas',
+ description: 'Work with your data in MongoDB Atlas Vector Store',
+ icon: { light: 'file:mongodb.svg', dark: 'file:mongodb.dark.svg' },
+ docsUrl:
+ 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.vectorstoremongodbatlas/',
+ credentials: [
+ {
+ name: 'mongoDb',
+ required: true,
+ },
+ ],
+ operationModes: ['load', 'insert', 'retrieve', 'update', 'retrieve-as-tool'],
+ },
+ methods: { listSearch: { mongoCollectionSearch } },
+ retrieveFields,
+ loadFields: retrieveFields,
+ insertFields,
+ sharedFields,
+ async getVectorStoreClient(context, _filter, embeddings, itemIndex) {
+ try {
+ const { db } = await mongoClientAndDatabase(context);
+ try {
+ const collectionName = context.getNodeParameter('mongoCollection', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const mongoVectorIndexName = context.getNodeParameter('vectorIndexName', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const embeddingFieldName = context.getNodeParameter('embedding', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const metadataFieldName = context.getNodeParameter('metadata_field', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const collection = db.collection(collectionName);
+
+ // test index exists
+ const indexes = await collection.listSearchIndexes().toArray();
+
+ const indexExists = indexes.some((index) => index.name === mongoVectorIndexName);
+
+ if (!indexExists) {
+ throw new NodeOperationError(
+ context.getNode(),
+ `Index ${mongoVectorIndexName} not found`,
+ {
+ itemIndex,
+ description: 'Please check that the index exists in your collection',
+ },
+ );
+ }
+
+ return new MongoDBAtlasVectorSearch(embeddings, {
+ collection,
+ indexName: mongoVectorIndexName, // Default index name
+ textKey: metadataFieldName, // Field containing raw text
+ embeddingKey: embeddingFieldName, // Field containing embeddings
+ });
+ } catch (error) {
+ throw new NodeOperationError(context.getNode(), `Error: ${error.message}`, {
+ itemIndex,
+ description: 'Please check your MongoDB Atlas connection details',
+ });
+ } finally {
+ // Don't close the client here to maintain connection pooling
+ }
+ } catch (error) {
+ throw new NodeOperationError(context.getNode(), `Error: ${error.message}`, {
+ itemIndex,
+ description: 'Please check your MongoDB Atlas connection details',
+ });
+ }
+ },
+ async populateVectorStore(context, embeddings, documents, itemIndex) {
+ try {
+ const { db } = await mongoClientAndDatabase(context);
+ try {
+ const mongoCollectionName = context.getNodeParameter('mongoCollection', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+ const embeddingFieldName = context.getNodeParameter('embedding', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const metadataFieldName = context.getNodeParameter('metadata_field', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ const mongoDBAtlasVectorIndex = context.getNodeParameter('vectorIndexName', itemIndex, '', {
+ extractValue: true,
+ }) as string;
+
+ // Check if collection exists
+ const collections = await db.listCollections({ name: mongoCollectionName }).toArray();
+ if (collections.length === 0) {
+ await db.createCollection(mongoCollectionName);
+ }
+ const collection = db.collection(mongoCollectionName);
+ await MongoDBAtlasVectorSearch.fromDocuments(documents, embeddings, {
+ collection,
+ indexName: mongoDBAtlasVectorIndex, // Default index name
+ textKey: metadataFieldName, // Field containing raw text
+ embeddingKey: embeddingFieldName, // Field containing embeddings
+ });
+ } catch (error) {
+ throw new NodeOperationError(context.getNode(), `Error: ${error.message}`, {
+ itemIndex,
+ description: 'Please check your MongoDB Atlas connection details',
+ });
+ } finally {
+ // Don't close the client here to maintain connection pooling
+ }
+ } catch (error) {
+ throw new NodeOperationError(context.getNode(), `Error: ${error.message}`, {
+ itemIndex,
+ description: 'Please check your MongoDB Atlas connection details',
+ });
+ }
+ },
+}) {}
diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.dark.svg b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.dark.svg
new file mode 100644
index 0000000000..3ccdc84421
--- /dev/null
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.svg b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.svg
new file mode 100644
index 0000000000..8da45829e2
--- /dev/null
+++ b/packages/@n8n/nodes-langchain/nodes/vector_store/VectorStoreMongoDBAtlas/mongodb.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/@n8n/nodes-langchain/package.json b/packages/@n8n/nodes-langchain/package.json
index 51a6672356..3418ee7fa3 100644
--- a/packages/@n8n/nodes-langchain/package.json
+++ b/packages/@n8n/nodes-langchain/package.json
@@ -109,6 +109,7 @@
"dist/nodes/vector_store/VectorStoreInMemory/VectorStoreInMemory.node.js",
"dist/nodes/vector_store/VectorStoreInMemoryInsert/VectorStoreInMemoryInsert.node.js",
"dist/nodes/vector_store/VectorStoreInMemoryLoad/VectorStoreInMemoryLoad.node.js",
+ "dist/nodes/vector_store/VectorStoreMongoDBAtlas/VectorStoreMongoDBAtlas.node.js",
"dist/nodes/vector_store/VectorStorePGVector/VectorStorePGVector.node.js",
"dist/nodes/vector_store/VectorStorePinecone/VectorStorePinecone.node.js",
"dist/nodes/vector_store/VectorStorePineconeInsert/VectorStorePineconeInsert.node.js",
@@ -129,8 +130,8 @@
"@types/json-schema": "^7.0.15",
"@types/mime-types": "^2.1.0",
"@types/pg": "^8.11.6",
- "@types/temp": "^0.9.1",
"@types/sanitize-html": "^2.11.0",
+ "@types/temp": "^0.9.1",
"n8n-core": "workspace:*"
},
"dependencies": {
@@ -150,6 +151,7 @@
"@langchain/google-vertexai": "0.1.8",
"@langchain/groq": "0.1.3",
"@langchain/mistralai": "0.2.0",
+ "@langchain/mongodb": "^0.1.0",
"@langchain/ollama": "0.1.4",
"@langchain/openai": "0.3.17",
"@langchain/pinecone": "0.1.3",
@@ -178,6 +180,7 @@
"lodash": "catalog:",
"mammoth": "1.7.2",
"mime-types": "2.1.35",
+ "mongodb": "6.11.0",
"n8n-nodes-base": "workspace:*",
"n8n-workflow": "workspace:*",
"openai": "4.78.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0aa23bcbcc..4f38521b90 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -521,7 +521,7 @@ importers:
version: 0.3.2(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0))(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))(encoding@0.1.13)
'@langchain/community':
specifier: 0.3.24
- version: 0.3.24(6476879575b309260030c283813e748d)
+ version: 0.3.24(1725dd003b6ba0539bce135b7f30abed)
'@langchain/core':
specifier: 'catalog:'
version: 0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1))
@@ -537,6 +537,9 @@ importers:
'@langchain/mistralai':
specifier: 0.2.0
version: 0.2.0(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))
+ '@langchain/mongodb':
+ specifier: ^0.1.0
+ version: 0.1.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)
'@langchain/ollama':
specifier: 0.1.4
version: 0.1.4(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))
@@ -563,7 +566,7 @@ importers:
version: link:../json-schema-to-zod
'@n8n/typeorm':
specifier: 0.3.20-12
- version: 0.3.20-12(@sentry/node@8.52.1)(ioredis@5.3.2)(mssql@10.0.2)(mysql2@3.11.0)(pg@8.12.0)(redis@4.6.12)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@18.16.16)(typescript@5.8.2))
+ version: 0.3.20-12(@sentry/node@8.52.1)(ioredis@5.3.2)(mongodb@6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3))(mssql@10.0.2)(mysql2@3.11.0)(pg@8.12.0)(redis@4.6.12)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@18.16.16)(typescript@5.8.2))
'@n8n/typescript-config':
specifier: workspace:*
version: link:../typescript-config
@@ -621,6 +624,9 @@ importers:
mime-types:
specifier: 2.1.35
version: 2.1.35
+ mongodb:
+ specifier: 6.11.0
+ version: 6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)
n8n-nodes-base:
specifier: workspace:*
version: link:../../nodes-base
@@ -4378,6 +4384,12 @@ packages:
peerDependencies:
'@langchain/core': '>=0.3.7 <0.4.0'
+ '@langchain/mongodb@0.1.0':
+ resolution: {integrity: sha512-5yO6aNMkdtxlJBjR8LFuvgDgnM/sbAhYe5AkN8VznPkpEoI6Pq4zjvl8gB3YTVpzdrp38HT5Z40VEwNEDHpwIw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@langchain/core': '>=0.2.21 <0.4.0'
+
'@langchain/ollama@0.1.4':
resolution: {integrity: sha512-olHPViUurGcmOI3IbhIGK/EJ7QxDlZru4j98V269PiEFTIVlciRULltgI/t3voHYTdvB8R+HV8pMo/Y3UVzvzA==}
engines: {node: '>=18'}
@@ -7042,6 +7054,7 @@ packages:
bson@6.10.0:
resolution: {integrity: sha512-ROchNosXMJD2cbQGm84KoP7vOGPO6/bOAW0veMMbzhXLqoZptcaYRVLitwvuhwhjjpU1qP4YZRWLhgETdgqUQw==}
engines: {node: '>=16.20.1'}
+ deprecated: a critical bug affecting only useBigInt64=true deserialization usage is fixed in bson@6.10.3
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
@@ -16501,7 +16514,7 @@ snapshots:
- aws-crt
- encoding
- '@langchain/community@0.3.24(6476879575b309260030c283813e748d)':
+ '@langchain/community@0.3.24(1725dd003b6ba0539bce135b7f30abed)':
dependencies:
'@browserbasehq/stagehand': 1.9.0(@playwright/test@1.49.1)(deepmerge@4.3.1)(dotenv@16.4.5)(encoding@0.1.13)(openai@4.78.1(encoding@0.1.13)(zod@3.24.1))(zod@3.24.1)
'@ibm-cloud/watsonx-ai': 1.1.2
@@ -16555,6 +16568,7 @@ snapshots:
jsonwebtoken: 9.0.2
lodash: 4.17.21
mammoth: 1.7.2
+ mongodb: 6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)
mysql2: 3.11.0
pdf-parse: 1.1.1
pg: 8.12.0
@@ -16649,6 +16663,19 @@ snapshots:
zod: 3.24.1
zod-to-json-schema: 3.23.3(zod@3.24.1)
+ '@langchain/mongodb@0.1.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)':
+ dependencies:
+ '@langchain/core': 0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1))
+ mongodb: 6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)
+ transitivePeerDependencies:
+ - '@aws-sdk/credential-providers'
+ - '@mongodb-js/zstd'
+ - gcp-metadata
+ - kerberos
+ - mongodb-client-encryption
+ - snappy
+ - socks
+
'@langchain/ollama@0.1.4(@langchain/core@0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1)))':
dependencies:
'@langchain/core': 0.3.30(openai@4.78.1(encoding@0.1.13)(zod@3.24.1))
@@ -16845,7 +16872,7 @@ snapshots:
esprima-next: 5.8.4
recast: 0.22.0
- '@n8n/typeorm@0.3.20-12(@sentry/node@8.52.1)(ioredis@5.3.2)(mssql@10.0.2)(mysql2@3.11.0)(pg@8.12.0)(redis@4.6.12)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@18.16.16)(typescript@5.8.2))':
+ '@n8n/typeorm@0.3.20-12(@sentry/node@8.52.1)(ioredis@5.3.2)(mongodb@6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3))(mssql@10.0.2)(mysql2@3.11.0)(pg@8.12.0)(redis@4.6.12)(sqlite3@5.1.7)(ts-node@10.9.2(@types/node@18.16.16)(typescript@5.8.2))':
dependencies:
'@n8n/p-retry': 6.2.0-2
'@sqltools/formatter': 1.2.5
@@ -16867,6 +16894,7 @@ snapshots:
optionalDependencies:
'@sentry/node': 8.52.1
ioredis: 5.3.2
+ mongodb: 6.11.0(@aws-sdk/credential-providers@3.666.0(@aws-sdk/client-sso-oidc@3.666.0(@aws-sdk/client-sts@3.666.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.3)
mssql: 10.0.2
mysql2: 3.11.0
pg: 8.12.0
@@ -21539,7 +21567,7 @@ snapshots:
eslint-import-resolver-node@0.3.9:
dependencies:
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
is-core-module: 2.13.1
resolve: 1.22.8
transitivePeerDependencies:
@@ -21564,7 +21592,7 @@ snapshots:
eslint-module-utils@2.8.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
dependencies:
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
optionalDependencies:
'@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.8.2)
eslint: 8.57.0
@@ -21584,7 +21612,7 @@ snapshots:
array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2
array.prototype.flatmap: 1.3.2
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
@@ -22362,7 +22390,7 @@ snapshots:
array-parallel: 0.1.3
array-series: 0.1.5
cross-spawn: 4.0.2
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
@@ -25234,7 +25262,7 @@ snapshots:
pdf-parse@1.1.1:
dependencies:
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
node-ensure: 0.0.0
transitivePeerDependencies:
- supports-color
@@ -26089,7 +26117,7 @@ snapshots:
rhea@1.0.24:
dependencies:
- debug: 3.2.7(supports-color@5.5.0)
+ debug: 3.2.7(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color