How to Build a Rich RAG App on MongoDB Compatible JSON

Madhukar Kumar
5 min readAug 18, 2024

--

A screenshot of the same RAG app that also shows rich analytics with each response to help customer support agents make real-time decisions.
A simulated Customer Co-pilot RAG App that also responds with rich analytics

I recently did a webinar where I walked through taking an existing RAG app on MongoDB and then moved it to SingleStore with zero code change and then added rich analytics to it.

Why do this?

Most RAG-based applications were initially restricted to text-based responses that required searching through unstructured data, but more recently, more and more enterprise customers have started to build internal-facing copilot apps for their employees. These apps require richer responses that query structured data and run analytics for decision-making.

In the webinar we asked the audience (mostly enterprise developers) if they are looking to build analytics in their AI apps. Here is the response.

The results of a live poll of audience that shows the results showing a majority of enterprise developers looking to add analytics to their RAG application

Note, that the sample side of respondents is very small but it gives a general directional idea in a very specific audience demography.

Ok, now that we have established that there is a possible need for making RAG responses richer with analytics, let’s address the elephant in the room. MongoDb is great for transactional use cases but not meant for analytics especially if it involves millions of rows and data points. This is where SingleStore comes in (for full transparency, I currently work for SingleStore). SingleStore is a distributed SQL database that handles all data types including MongoDB compatible JSON and can run analytics over billions of rows of data (petabyte scale) with millisecond response times. Best of all, due to MongoDB API compatibility you don’t have to move all your data and you can mix and match JSON data with analytics SQL queries.

Here are the steps of how to do this for a very simple MongoDB/NextJS app that works with no code change in SingleStore and once we get that working we add the analytics query to all RAG response (see screenshot below) 👇

Steps to try this out

Prerequisites

  • Basic understanding of MongoDB, Next.js, JavaScript, and SQL.
  • Access to a MongoDB cluster (you can use MongoDB Atlas for this).
  • A SingleStore account (you can sign up for a free trial at SingleStore).
  • Node.js installed on your local machine.
  • A text editor or IDE, such as Visual Studio Code.

Step 1: Setting Up the MongoDB App

1. Clone the Starter App Repository

  • Go to the MongoDB Partners GitHub page and clone the starter app repository.
  • Open your terminal and run the following command:
git clone https://github.com/mongodb-partners/MongoDB-RAG-Vercel
cd MongoDB-RAG-Vercel

2. Install Dependencies

  • After navigating to the cloned directory, install the necessary dependencies using pnpm (or npm if you prefer):
pnpm install

3. Set Up Environment Variables

  • Copy the example environment file to create your own .env file:
cp .env.example .env
  • Open the .env file in your text editor and replace the placeholder values with your actual MongoDB connection string and OpenAI API key. For example:
MONGODB_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net/<dbname>?retryWrites=true&w=majority
OPENAI_API_KEY=your-openai-api-key

4. Run the Application

  • Start the development server:
pnpm run dev

Step 2: Creating a Vector Index in MongoDB

  • Create a MongoDB Cluster (if not already created)
  • If you haven’t set up a MongoDB cluster yet, create a free tier cluster on MongoDB Atlas.

2. Create a Vector Index

  • Access your MongoDB cluster and navigate to the “Indexes” tab.
  • Create a new index and select the “Search” option.
  • Name your index (e.g., VectorIndex) and choose the appropriate collection.
  • Use the following JSON command to define your vector index:
{
“mappings”: {
“dynamic”: false,
“fields”: {
“embedding”: {
“type”: “knn_vector”,
“dimensions”: 512
}
}
}
}

Step 3: Integrating with SingleStore

1. Sign up for a free tier on SingleStore. This should create a workspace and a database for you that is MongoDB compatible.

  • Once the workspace is created, take note of the connection string provided under the “Connect” tab, specifically for MongoDB clients.

2. Update the Connection String

  • In your project, update the MongoDB connection string in your .env file to point to SingleStore. Replace the existing MONGODB_URI with the SingleStore Kai connection string.

3. Create a New Database and Collections in SingleStore

  • Use the SingleStore Data Studio or connect via a MongoDB client to create your database and collections.
  • Follow the same step as above by simply running the following command and then opening the URL and uploading a pdf document.
pnpm run dev

Step 4: Adding Analytics to Your Application

1. Create Structured Data for Analytics

  • In SingleStore, create a new table to store structured data for analytics. For example, create a CustomerIncidents table (note this is a trivial example) :
CREATE TABLE CustomerIncidents (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_name VARCHAR(255),
total_revenue DECIMAL(10, 2),
tickets_opened INT,
last_24_hours INT,
sentiment VARCHAR(20)
);
  • Populate this table with synthetic or real data relevant to your use case.

2. Implement Analytics in the Application

  • In your Next.js app, create a new API endpoint (e.g., pages/api/insights.js) to query the analytics data from SingleStore.
  • Example API endpoint code:
import { connectToDatabase } from ‘../../util/mongodb’;
import sql from ‘../../util/singlestore’;
export default async (req, res) => {
const { db } = await connectToDatabase();

const query = `SELECT * FROM CustomerIncidents WHERE sentiment = ‘negative’ LIMIT 10`;
const incidents = await sql.query(query);
res.json({ incidents });
};

3. Create a New UI Component for Insights

  • Create a new page in your app (e.g., pages/insights.js) that displays the data retrieved from the new API endpoint.
  • Example code:
import { useState, useEffect } from 'react';
export default function Insights() {
const [data, setData] = useState([]);
useEffect(() => {
async function fetchData() {
const response = await fetch('/api/insights');
const result = await response.json();
setData(result.incidents);
}
fetchData();
}, []);
return (
<div>
<h1>Customer Insights</h1>
<ul>
{data.map(incident => (
<li key={incident.id}>
{incident.customer_name} - {incident.total_revenue} - {incident.sentiment}
</li>
))}
</ul>
</div>
);
}

4. Run and Test the Enhanced Application

  • Restart your development server and navigate to the new insights page (http://localhost:3000/insights) to see the analytics in action.

You can clone this repo with the added analytics example from here:

https://github.com/singlestore-labs/kai-rag

Conclusion

We took a simple MongoDB-based full-stack application into a high-performance, analytics-rich solution using SingleStore. This hybrid approach allows you to leverage the strengths of both JSON and relational databases, enabling you to build scalable and efficient applications that can handle both transactional and analytical workloads.

Feel free to explore further enhancements and customizations to tailor this setup to your specific needs. Happy coding!

✌️

--

--

Madhukar Kumar

CMO @SingleStore, tech buff, ind developer, hacker, distance runner ex @redislabs ex @zuora ex @oracle. My views are my own