This workflow follows the Agent → Google Gemini Embeddings recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "ReviewFlow",
"nodes": [
{
"parameters": {
"workflowInputs": {
"values": [
{
"name": "text"
},
{
"name": "userId"
},
{
"name": "token"
}
]
}
},
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
-240,
-40
],
"id": "74328233-7f45-4060-ae95-1e9698e7339f",
"name": "When Executed by Another Workflow"
},
{
"parameters": {
"method": "POST",
"url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=<redacted-credential>",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "raw",
"rawContentType": "JSON",
"body": "={\n \"contents\": [\n {\n \"role\": \"user\",\n \"parts\": [\n {\n \"text\": \"B\u1ea1n l\u00e0 AI ph\u00e2n lo\u1ea1i c\u00e2u h\u1ecfi ng\u01b0\u1eddi d\u00f9ng \u0111\u1ec3 h\u1ed7 tr\u1ee3 tr\u1ee3 l\u00fd \u1ea3o x\u1eed l\u00fd \u0111\u00e1nh gi\u00e1.\nH\u00e3y ph\u00e2n lo\u1ea1i to\u00e0n b\u1ed9 \u0111o\u1ea1n h\u1ed9i tho\u1ea1i g\u1ea7n nh\u1ea5t th\u00e0nh **m\u1ed9t trong b\u1ed1n nh\u00f3m sau**:\n1. **H\u1ecfi v\u1ec1 \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m**: Xem \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m\n2. **Th\u00eam v\u00e0o \u0111\u00e1nh gi\u00e1**: Y\u00eau c\u1ea7u th\u00eam \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m \n3. **Ch\u1ec9nh s\u1eeda \u0111\u00e1nh gi\u00e1**: Y\u00eau c\u1ea7u ch\u1ec9nh s\u1eeda \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m \n **Ch\u1ec9 tr\u1ea3 v\u1ec1 duy nh\u1ea5t m\u1ed9t s\u1ed1**: 1, 2 ho\u1eb7c 3 (kh\u00f4ng c\u1ea7n gi\u1ea3i th\u00edch).\n\u0110o\u1ea1n h\u1ed9i tho\u1ea1i g\u1ea7n nh\u1ea5t:\\n\\\"{{ $json.text }}\\\"\"\n }\n ]\n }\n ]\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
20,
-40
],
"id": "321285de-189f-4651-b22b-bb91f1bf772d",
"name": "Ph\u00e2n Lo\u1ea1i"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.candidates[0].content.parts[0].text }}",
"rightValue": "1",
"operator": {
"type": "string",
"operation": "contains"
},
"id": "58a31e11-ef29-4b7a-9e48-a29b805251e9"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "b8577749-bb33-46ce-a640-15e6ead32b5c",
"leftValue": "={{ $json.candidates[0].content.parts[0].text }}",
"rightValue": "2",
"operator": {
"type": "string",
"operation": "contains"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "7adb4c1f-a428-4aa0-8a1d-17638f941ea0",
"leftValue": "={{ $json.candidates[0].content.parts[0].text }}",
"rightValue": "3",
"operator": {
"type": "string",
"operation": "contains"
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
240,
-40
],
"id": "32450679-cdcc-4e23-8398-8aa38a809eb7",
"name": "Switch"
},
{
"parameters": {
"jsCode": "const input = $('When Executed by Another Workflow').first().json;\nconst text = input.text?.toLowerCase() || '';\n\n// Regex: L\u1ea5y t\u00ean s\u1ea3n ph\u1ea9m \u1edf cu\u1ed1i c\u00e2u (sau \"s\u1ea3n ph\u1ea9m\", \"v\u1ec1\", \"c\u1ee7a\", v.v.)\nconst productMatch = text.match(/(?:v\u1ec1|s\u1ea3n ph\u1ea9m|c\u1ee7a)\\s+(.*?)(\\?|$)/i);\n\n// X\u00e1c \u0111\u1ecbnh intent \"review-query\"\nconst isReviewQuery = /\u0111\u00e1nh gi\u00e1|m\u1ecdi ng\u01b0\u1eddi ngh\u0129|c\u00f3 ai d\u00f9ng|b\u1ecb l\u1ed7i/i.test(text);\n\nreturn [\n {\n json: {\n productName: productMatch ? productMatch[1].trim() : null,\n // intent: isReviewQuery ? \"review-query\" : \"other\",\n text: text\n }\n }\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
-320
],
"id": "37e4b70c-9574-4d0d-b91f-1f584ef520ec",
"name": "Code"
},
{
"parameters": {
"collection": "products",
"options": {},
"query": "={\n \"name\": { \"$regex\": \"{{ $json.productName }}\", \"$options\": \"i\" },\n \"isDeleted\": null,\n \"isVerified\": { \"$ne\": null }\n}\n"
},
"type": "n8n-nodes-base.mongoDb",
"typeVersion": 1.1,
"position": [
720,
-320
],
"id": "e56bbb9d-ad14-45c9-84ab-9774d178493d",
"name": "MongoDB",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "aggregate",
"collection": "reviews",
"query": "=[\n { \"$match\": {\n \"$expr\": {\n \"$eq\": [\n \"$product\",\n { \"$toObjectId\": \"{{ $json._id }}\" }\n ]\n }\n }\n },\n { \"$sort\": { \"createdAt\": -1 } },\n { \"$limit\": 5 },\n {\n \"$lookup\": {\n \"from\": \"users\",\n \"localField\": \"user\",\n \"foreignField\": \"_id\",\n \"as\": \"userInfo\"\n }\n },\n {\n \"$unwind\": {\n \"path\": \"$userInfo\",\n \"preserveNullAndEmptyArrays\": true\n }\n },\n {\n \"$project\": {\n \"star\": 1,\n \"comment\": 1,\n \"createdAt\": 1,\n \"userName\": \"$userInfo.name\"\n }\n }\n]\n"
},
"type": "n8n-nodes-base.mongoDb",
"typeVersion": 1.1,
"position": [
1000,
-320
],
"id": "0b012c42-1ce2-4592-a42e-435294279c63",
"name": "MongoDB1",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const reviews = $input.all();\n\nif (reviews.length === 0) {\n return [\n {\n json: {\n context: \"Ch\u01b0a c\u00f3 ai \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m n\u00e0y.\"\n }\n }\n ];\n}\n\nconst formatted = reviews.map((r, i) => {\n const name = r.json.userName || \"Ng\u01b0\u1eddi d\u00f9ng \u1ea9n danh\";\n const star = \"\u2b50\".repeat(r.json.star || 0);\n const comment = r.json.comment || \"(Kh\u00f4ng c\u00f3 b\u00ecnh lu\u1eadn)\";\n return `${i + 1}. ${name} (${star}): ${comment}`;\n});\n\nconst context = `D\u01b0\u1edbi \u0111\u00e2y l\u00e0 m\u1ed9t s\u1ed1 \u0111\u00e1nh gi\u00e1 g\u1ea7n \u0111\u00e2y t\u1eeb ng\u01b0\u1eddi d\u00f9ng:\\n${formatted.join(\"\\n\")}`;\n\nreturn [\n {\n json: {\n context\n }\n }\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1280,
-320
],
"id": "bec1b50d-6a55-4537-9762-68982843dba2",
"name": "Context"
},
{
"parameters": {
"promptType": "define",
"text": "=\u0111\u00e2y l\u00e0 y\u00eau c\u1ea7u c\u1ee7a ng\u01b0\u1eddi d\u00f9ng: \"{{ $('When Executed by Another Workflow').first().json.text }}\"\nDanh s\u00e1ch \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m: \n{{ $json.context }}\nH\u00e3y xem y\u00eau c\u1ea7u c\u1ee7a ng\u01b0\u1eddi d\u00f9ng v\u00e0 \u0111\u01b0a ra c\u00e2u tr\u1ea3 l\u1eddi theo y\u00eau c\u1ea7u. N\u1ebfu c\u00f3 nh\u1eefng \u0111\u00e1nh gi\u00e1 kh\u00f4ng li\u00ean quan \u0111\u1ebfn s\u1ea3n ph\u1ea9m th\u00ec b\u1ecf qua",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
1480,
-320
],
"id": "b5b1d414-58a5-455b-9455-35ae25f5df33",
"name": "AI Agent"
},
{
"parameters": {
"modelName": "models/gemini-2.0-flash",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
1480,
-160
],
"id": "a756a5b5-0844-4236-bcf6-5d7b067070b0",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "load",
"mongoCollection": {
"__rl": true,
"value": "products",
"mode": "list",
"cachedResultName": "products"
},
"metadata_field": "metadata",
"vectorIndexName": "vector_index_products",
"prompt": "={{ $('When Executed by Another Workflow').item.json.text }}",
"topK": 2,
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreMongoDBAtlas",
"typeVersion": 1.1,
"position": [
660,
60
],
"id": "1674b9fa-63db-477d-bae8-851abd38f4ea",
"name": "MongoDB Atlas Vector Store",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"modelName": "models/embedding-001"
},
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"typeVersion": 1,
"position": [
840,
180
],
"id": "4d445191-769e-44f1-896b-14ac7a75a4c3",
"name": "Embeddings Google Gemini",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const input = $('When Executed by Another Workflow').first().json.text.toLowerCase();\n\nconst result = {\n intent: 'unknown',\n rating: null,\n comment: null,\n price: null\n};\n\n// \u2b50 Match \u0111i\u1ec3m sao\nconst ratingMatch = input.match(/([1-5])\\s*sao/);\nif (ratingMatch) {\n result.rating = parseInt(ratingMatch[1]);\n\n // \u01afu ti\u00ean t\u00e1ch comment sau c\u00e1c t\u1eeb kh\u00f3a nh\u01b0 v\u00ec/do/t\u1ea1i...\n const reasonMatch = input.match(/(?:v\u00ec|do|t\u1ea1i|l\u00fd do l\u00e0)\\s+(.*)/i);\n if (reasonMatch) {\n result.comment = reasonMatch[1].trim();\n } else {\n // N\u1ebfu kh\u00f4ng c\u00f3 t\u1eeb kh\u00f3a th\u00ec l\u1ea5y ph\u1ea7n sau \"X sao\"\n const commentStart = input.indexOf(ratingMatch[0]) + ratingMatch[0].length;\n const comment = input.slice(commentStart).trim();\n if (comment.length > 0) result.comment = comment;\n }\n}\n\n// \ud83d\udcb0 Match gi\u00e1 ti\u1ec1n (d\u00f9 kh\u00f4ng c\u00f3 \u0111\u01a1n v\u1ecb)\nconst priceMatch = input.match(/gi\u00e1\\s*(\\d+)/i);\nif (priceMatch) {\n result.price = parseInt(priceMatch[1]);\n}\n\n\n// \u2705 Intent x\u00e1c \u0111\u1ecbnh n\u1ebfu ch\u1ee9a t\u1eeb kh\u00f3a\nif (input.includes('\u0111\u00e1nh gi\u00e1') || input.includes('ch\u1ea5m \u0111i\u1ec3m') || input.includes('review')) {\n result.intent = 'post_review';\n}\n\nreturn [{ json: result }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
60
],
"id": "43a788e2-226d-4338-9f6f-77f993173554",
"name": "Code1"
},
{
"parameters": {
"operation": "aggregate",
"collection": "orders",
"query": "=[\n {\n \"$match\": {\n \"$expr\": {\n \"$and\": [\n {\n \"$eq\": [\n \"$user\",\n { \"$toObjectId\": \"{{ $json.userId }}\"}\n ]\n },\n {\n \"$eq\": [\n \"$product\",\n { \"$toObjectId\": \"{{ $json._id }}\" }\n ]\n },\n {\n \"$in\": [\n \"$status.currentStatus\",\n [\"approve\", \"return\"]\n ]\n }\n ]\n }\n }\n },\n { \"$limit\": 1 }\n]\n"
},
"type": "n8n-nodes-base.mongoDb",
"typeVersion": 1.1,
"position": [
1420,
60
],
"id": "6be0e6ed-44e2-489a-85a9-045b05809fb1",
"name": "MongoDB2",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "cadfbfd2-faa1-4d8c-ad40-ecdd711849c2",
"leftValue": "={{ $items.length > 0 }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1620,
60
],
"id": "d17312f9-1d3f-4a92-9caf-1b3792893c25",
"name": "Item > 0"
},
{
"parameters": {
"method": "POST",
"url": "=http://host.docker.internal:3001/api/review-qna/review/{{ $('Code3').item.json.slug }}\n",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "x-auth-token",
"value": "={{ $('Code3').item.json.token }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"star\": {{ $('Code3').item.json.rating }},\n \"comment\": \"{{ $('Code3').item.json.comment }}\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1900,
-40
],
"id": "9550daf9-0470-446f-a2d0-2e0c31234b5a",
"name": "add"
},
{
"parameters": {
"promptType": "define",
"text": "B\u1ea1n ch\u1ec9 c\u1ea7n th\u00f4ng b\u00e1o v\u1edbi Ng\u01b0\u1eddi d\u00f9ng l\u00e0 \" T\u00f4i \u0111\u00e3 th\u00eam \u0111\u00e1nh gi\u00e1 th\u00e0nh c\u00f4ng.\"\n",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
2120,
-40
],
"id": "054b30ea-db31-4197-a7c7-792bd5b9897a",
"name": "AI Agent1"
},
{
"parameters": {
"modelName": "models/gemini-2.0-flash",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
2120,
140
],
"id": "6adf27fd-e8f1-42da-8f77-1b1529655f57",
"name": "Google Gemini Chat Model1",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"promptType": "define",
"text": "B\u1ea1n ch\u1ec9 c\u1ea7n th\u00f4ng b\u00e1o v\u1edbi Ng\u01b0\u1eddi d\u00f9ng l\u00e0 \n\"B\u1ea1n ch\u01b0a mua s\u1ea3n ph\u1ea9m n\u00e0y\"",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
1780,
220
],
"id": "f0096ce5-7240-412b-ac2c-c87fc0ef7915",
"name": "AI Agent2"
},
{
"parameters": {
"modelName": "models/gemini-2.0-flash",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
1760,
380
],
"id": "3090859d-2a81-405c-9bdf-cd4b607fb72e",
"name": "Google Gemini Chat Model2",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const inputItems = $input.all();\nconst expectedRaw = $('Code1').first().json.price;\nconst expectedPrice = expectedRaw ? parseFloat(expectedRaw) : null;\nconst priceRange = 1000;\n\nfor (const item of inputItems) {\n const product = item.json.document?.metadata || item.json;\n\n if (!product || !product.price) continue;\n\n let price = 0;\n if (typeof product.price === 'object' && '$numberDecimal' in product.price) {\n price = parseFloat(product.price.$numberDecimal);\n } else if (typeof product.price === 'number') {\n price = product.price;\n }\n\n // \ud83d\udd0d N\u1ebfu c\u00f3 expectedPrice th\u00ec so s\u00e1nh\n if (expectedPrice !== null) {\n if (price > 0 && Math.abs(price - expectedPrice) <= priceRange) {\n return [{\n json: {\n _id: product._id?.$oid || product._id,\n name: product.name || \"Kh\u00f4ng r\u00f5\",\n slug: product.slug\n }\n }];\n }\n }\n}\n\n// \u2705 N\u1ebfu kh\u00f4ng c\u00f3 gi\u00e1 tr\u1ecb mong mu\u1ed1n ho\u1eb7c kh\u00f4ng t\u00ecm \u0111\u01b0\u1ee3c => fallback l\u1ea5y s\u1ea3n ph\u1ea9m \u0111\u1ea7u ti\u00ean\nif (inputItems.length > 0) {\n const product = inputItems[0].json.document?.metadata || inputItems[0].json;\n return [{\n json: {\n _id: product._id?.$oid || product._id,\n name: product.name || \"Kh\u00f4ng r\u00f5\",\n slug: product.slug\n }\n }];\n}\n\n// \u274c N\u1ebfu kh\u00f4ng c\u00f3 s\u1ea3n ph\u1ea9m n\u00e0o c\u1ea3\nreturn [{\n json: {\n message: \"Kh\u00f4ng t\u00ecm th\u1ea5y s\u1ea3n ph\u1ea9m n\u00e0o ph\u00f9 h\u1ee3p.\"\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1020,
60
],
"id": "3c7bbcff-7c42-434c-93b6-2b6339e25997",
"name": "Code2"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// \u2705 L\u1ea5y d\u1eef li\u1ec7u t\u1eeb node g\u1ed1c (ch\u1ec9 l\u1ea5y 1 l\u1ea7n)\nconst userId = $('When Executed by Another Workflow').first().json.userId;\nconst token = $('When Executed by Another Workflow').first().json.token;\nconst rating = $('Code1').first().json.rating;\nconst comment = $('Code1').first().json.comment;\n\n// \u2705 G\u00e1n v\u00e0o t\u1eebng item \u0111ang x\u1eed l\u00fd\nitem.json.userId = userId;\nitem.json.token = token;\nitem.json.rating = rating;\nitem.json.comment = comment;\n\n// \u2705 Tr\u1ea3 l\u1ea1i item m\u1edbi\nreturn item;\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1220,
60
],
"id": "20be86c8-caf9-4c2d-992f-1aaba375533a",
"name": "Code3"
},
{
"parameters": {
"jsCode": "const input = $('When Executed by Another Workflow').first().json.text.toLowerCase();\nconst result = {\n product_name: null,\n rating: null,\n comment: null,\n price: null\n};\n\n// T\u00e1ch s\u1ed1 sao\nconst starMatch = input.match(/([1-5])\\s*sao/);\nif (starMatch) result.rating = parseInt(starMatch[1]);\n\n// T\u00e1ch comment: sau \"v\u00ec\", \"do\", \"t\u1ea1i\", \"l\u00fd do l\u00e0\"\nconst reasonMatch = input.match(/(?:v\u00ec|do|t\u1ea1i|l\u00fd do l\u00e0)\\s+(.+)/i);\nif (reasonMatch) result.comment = reasonMatch[1].trim();\n\n// T\u00e1ch t\u00ean s\u1ea3n ph\u1ea9m\nconst productMatch = input.match(/s\u1ea3n ph\u1ea9m\\s+(.+?)(?=\\s+gi\u00e1|\\s+\\d\\s*sao|\\s+v\u00ec|$)/i);\nif (productMatch) result.product_name = productMatch[1].trim();\n\nconst priceMatch = input.match(/gi\u00e1\\s*(\\d+)/i);\nif (priceMatch) {\n result.price = parseInt(priceMatch[1]);\n}\n\nreturn [{ json: result }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
560
],
"id": "d27c38c9-f9d6-4fcc-8b87-e9c3cb81c1ae",
"name": "Code4"
},
{
"parameters": {
"mode": "load",
"mongoCollection": {
"__rl": true,
"value": "products",
"mode": "list",
"cachedResultName": "products"
},
"metadata_field": "metadata",
"vectorIndexName": "vector_index_products",
"prompt": "={{ $json.product_name }}",
"topK": 2,
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreMongoDBAtlas",
"typeVersion": 1.1,
"position": [
680,
560
],
"id": "02ca9b6d-3189-4d9e-a884-80dbc9dffe07",
"name": "MongoDB Atlas Vector Store1",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"modelName": "models/embedding-001"
},
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"typeVersion": 1,
"position": [
820,
680
],
"id": "3f1adc15-903c-4b25-9994-b2a35d0bca39",
"name": "Embeddings Google Gemini1",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const inputItems = $input.all();\nconst expectedRaw = $('Code4').first().json.price;\nconst expectedPrice = expectedRaw ? parseFloat(expectedRaw) : null;\nconst priceRange = 1000;\n\nfor (const item of inputItems) {\n const product = item.json.document?.metadata || item.json;\n\n if (!product || !product.price) continue;\n\n let price = 0;\n if (typeof product.price === 'object' && '$numberDecimal' in product.price) {\n price = parseFloat(product.price.$numberDecimal);\n } else if (typeof product.price === 'number') {\n price = product.price;\n }\n\n // \ud83d\udd0d N\u1ebfu c\u00f3 expectedPrice th\u00ec so s\u00e1nh\n if (expectedPrice !== null) {\n if (price > 0 && Math.abs(price - expectedPrice) <= priceRange) {\n return [{\n json: {\n _id: product._id?.$oid || product._id,\n name: product.name || \"Kh\u00f4ng r\u00f5\",\n slug: product.slug\n }\n }];\n }\n }\n}\n\n// \u2705 N\u1ebfu kh\u00f4ng c\u00f3 gi\u00e1 tr\u1ecb mong mu\u1ed1n ho\u1eb7c kh\u00f4ng t\u00ecm \u0111\u01b0\u1ee3c => fallback l\u1ea5y s\u1ea3n ph\u1ea9m \u0111\u1ea7u ti\u00ean\nif (inputItems.length > 0) {\n const product = inputItems[0].json.document?.metadata || inputItems[0].json;\n return [{\n json: {\n _id: product._id?.$oid || product._id,\n name: product.name || \"Kh\u00f4ng r\u00f5\",\n slug: product.slug\n }\n }];\n}\n\n// \u274c N\u1ebfu kh\u00f4ng c\u00f3 s\u1ea3n ph\u1ea9m n\u00e0o c\u1ea3\nreturn [{\n json: {\n message: \"Kh\u00f4ng t\u00ecm th\u1ea5y s\u1ea3n ph\u1ea9m n\u00e0o ph\u00f9 h\u1ee3p.\"\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1080,
560
],
"id": "1876865b-7d1e-4cfd-9d5a-a222b47b6766",
"name": "Code5"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// \u2705 L\u1ea5y d\u1eef li\u1ec7u t\u1eeb node g\u1ed1c (ch\u1ec9 l\u1ea5y 1 l\u1ea7n)\nconst userId = $('When Executed by Another Workflow').first().json.userId;\nconst token = $('When Executed by Another Workflow').first().json.token;\nconst rating = $('Code4').first().json.rating;\nconst comment = $('Code4').first().json.comment;\n\n// \u2705 G\u00e1n v\u00e0o t\u1eebng item \u0111ang x\u1eed l\u00fd\nitem.json.userId = userId;\nitem.json.token = token;\nitem.json.rating = rating;\nitem.json.comment = comment;\n\n// \u2705 Tr\u1ea3 l\u1ea1i item m\u1edbi\nreturn item;\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
560
],
"id": "cdad15d4-9510-4662-8383-f7749c9fdfad",
"name": "Code6"
},
{
"parameters": {
"operation": "aggregate",
"collection": "reviews",
"query": "=[\n {\n \"$match\": {\n \"$expr\": {\n \"$and\": [\n { \"$eq\": [ \"$user\", { \"$toObjectId\": \"{{ $('Code6').item.json.userId }}\" } ] },\n { \"$eq\": [ \"$product\", { \"$toObjectId\": \"{{ $('Code5').item.json._id }}\" } ] }\n ]\n }\n }\n },\n { \"$limit\": 1 }\n]\n"
},
"type": "n8n-nodes-base.mongoDb",
"typeVersion": 1.1,
"position": [
1560,
560
],
"id": "7cb5ded5-2681-488e-a509-66e303ff418f",
"name": "MongoDB3",
"credentials": {
"mongoDb": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "cadfbfd2-faa1-4d8c-ad40-ecdd711849c2",
"leftValue": "={{ $items.length > 0 }}",
"rightValue": "true",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1740,
560
],
"id": "8e678d25-2de5-4096-a0bf-f7b15fd7c3a2",
"name": "Item > "
},
{
"parameters": {
"method": "PUT",
"url": "=http://host.docker.internal:3001/api/review-qna/review/{{ $('Code6').item.json.slug }}/{{ $('MongoDB3').item.json._id }}\n",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "x-auth-token",
"value": "={{ $('Code6').item.json.token }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"star\": {{ $('Code6').item.json.rating }},\n \"comment\": \"{{ $('Code6').item.json.comment }}\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2020,
480
],
"id": "fcdc3317-0bd1-49f5-9235-0fa479bced0b",
"name": "edit"
},
{
"parameters": {
"promptType": "define",
"text": "B\u1ea1n ch\u1ec9 c\u1ea7n th\u00f4ng b\u00e1o v\u1edbi Ng\u01b0\u1eddi d\u00f9ng l\u00e0 \" T\u00f4i \u0111\u00e3 s\u1eeda \u0111\u00e1nh gi\u00e1 th\u00e0nh c\u00f4ng.\"\n",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
2240,
480
],
"id": "dad5e362-cced-405a-adb3-00857daedaa2",
"name": "AI Agent3"
},
{
"parameters": {
"modelName": "models/gemini-2.0-flash",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
2220,
620
],
"id": "04068325-0842-4944-839d-a9ef8be4a1e1",
"name": "Google Gemini Chat Model3",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"promptType": "define",
"text": "B\u1ea1n ch\u1ec9 c\u1ea7n th\u00f4ng b\u00e1o v\u1edbi Ng\u01b0\u1eddi d\u00f9ng l\u00e0 \n\"B\u1ea1n ch\u01b0a \u0111\u00e1nh gi\u00e1 s\u1ea3n ph\u1ea9m n\u00e0y\"",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 2,
"position": [
1980,
740
],
"id": "1fbb7c8e-aff5-4277-a937-ec5b8da9f68d",
"name": "AI Agent4"
},
{
"parameters": {
"modelName": "models/gemini-2.0-flash",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
1940,
880
],
"id": "4c234f2c-ebd1-451c-aad5-bcda8caf2a91",
"name": "Google Gemini Chat Model4",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"When Executed by Another Workflow": {
"main": [
[
{
"node": "Ph\u00e2n Lo\u1ea1i",
"type": "main",
"index": 0
}
]
]
},
"Ph\u00e2n Lo\u1ea1i": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
],
[
{
"node": "Code1",
"type": "main",
"index": 0
}
],
[
{
"node": "Code4",
"type": "main",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "MongoDB",
"type": "main",
"index": 0
}
]
]
},
"MongoDB": {
"main": [
[
{
"node": "MongoDB1",
"type": "main",
"index": 0
}
]
]
},
"MongoDB1": {
"main": [
[
{
"node": "Context",
"type": "main",
"index": 0
}
]
]
},
"Context": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Embeddings Google Gemini": {
"ai_embedding": [
[
{
"node": "MongoDB Atlas Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"MongoDB Atlas Vector Store": {
"main": [
[
{
"node": "Code2",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "MongoDB Atlas Vector Store",
"type": "main",
"index": 0
}
]
]
},
"MongoDB2": {
"main": [
[
{
"node": "Item > 0",
"type": "main",
"index": 0
}
]
]
},
"Item > 0": {
"main": [
[
{
"node": "add",
"type": "main",
"index": 0
}
],
[
{
"node": "AI Agent2",
"type": "main",
"index": 0
}
]
]
},
"add": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Google Gemini Chat Model2": {
"ai_languageModel": [
[
{
"node": "AI Agent2",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Code2": {
"main": [
[
{
"node": "Code3",
"type": "main",
"index": 0
}
]
]
},
"Code3": {
"main": [
[
{
"node": "MongoDB2",
"type": "main",
"index": 0
}
]
]
},
"Code4": {
"main": [
[
{
"node": "MongoDB Atlas Vector Store1",
"type": "main",
"index": 0
}
]
]
},
"Embeddings Google Gemini1": {
"ai_embedding": [
[
{
"node": "MongoDB Atlas Vector Store1",
"type": "ai_embedding",
"index": 0
}
]
]
},
"MongoDB Atlas Vector Store1": {
"main": [
[
{
"node": "Code5",
"type": "main",
"index": 0
}
]
]
},
"Code5": {
"main": [
[
{
"node": "Code6",
"type": "main",
"index": 0
}
]
]
},
"Code6": {
"main": [
[
{
"node": "MongoDB3",
"type": "main",
"index": 0
}
]
]
},
"MongoDB3": {
"main": [
[
{
"node": "Item > ",
"type": "main",
"index": 0
}
]
]
},
"Item > ": {
"main": [
[
{
"node": "edit",
"type": "main",
"index": 0
}
],
[
{
"node": "AI Agent4",
"type": "main",
"index": 0
}
]
]
},
"edit": {
"main": [
[
{
"node": "AI Agent3",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model3": {
"ai_languageModel": [
[
{
"node": "AI Agent3",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Google Gemini Chat Model4": {
"ai_languageModel": [
[
{
"node": "AI Agent4",
"type": "ai_languageModel",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "06b8ca0a-746b-4abd-839a-ad17f2eabcad",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "t3BUmBAfLHPBR5xP",
"tags": []
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googlePalmApimongoDb
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
ReviewFlow. Uses executeWorkflowTrigger, httpRequest, mongoDb, agent. Event-driven trigger; 33 nodes.
Source: https://github.com/nav0114/khoaluantotnghiep/blob/d4c85a79b0a96e75576253ea24a3d20f742ba27a/n8n/ReviewFlow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This template is a complete, hands-on tutorial for building a RAG (Retrieval-Augmented Generation) pipeline. In simple terms, you'll teach an AI to become an expert on a specific topic—in this case, t
Api Schema Extractor. Uses manualTrigger, httpRequest, splitOut, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 88 nodes.
Wait Splitout. Uses manualTrigger, httpRequest, splitOut, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 88 nodes.
This workflow automates the process of discovering and extracting APIs from various services, followed by generating custom schemas. It works in three distinct stages: research, extraction, and schema
📌 Overview