MongoDB to SQL Query Converter
Paste a mongosh query and get the equivalent SQL SELECT. The converter reads db.collection.find() with filter, projection, sort, skip and limit, plus findOne, countDocuments, distinct and aggregate() pipelines. Filter operators such as $eq, $ne, $gt, $in, $nin, $exists, $and, $or, $nor and $not become WHERE conditions (with the extra IS NULL checks MongoDB semantics require), simple regular expressions become LIKE or ILIKE, and dotted paths like address.city become JSON access or flattened columns. In pipelines, $match turns into WHERE or HAVING depending on its position, $group into GROUP BY with COUNT, SUM, AVG, MIN and MAX, $lookup plus $unwind into a LEFT or INNER JOIN, and stage orders one SELECT cannot express are wrapped in subqueries. Output targets PostgreSQL, MySQL, SQL Server or SQLite, with a clause-by-clause mapping and explicit warnings for anything without a SQL equivalent. Parsing happens in your browser; the query is never uploaded or evaluated as code.
Do more than mongodb to sql query converter — meet Chat2DB
Chat2DB is an AI-powered SQL client for Windows, macOS and Linux. Write SQL in natural language, format and optimize queries automatically, and manage MySQL, PostgreSQL, Oracle and 20+ other databases in one workspace.
How to use
- Paste a MongoDB shell query such as db.orders.find({...}).sort({...}).limit(10) or db.orders.aggregate([...]), or load one of the samples.
- Choose the target SQL dialect and how dotted field paths should be mapped: JSON access on a document column, or flattened column names.
- Copy the generated SQL, then read the clause mapping and warnings to review anything that behaves differently in SQL, such as null handling or untranslated operators.
Frequently asked questions
How are MongoDB $lookup and $unwind converted to SQL?
A $lookup with localField and foreignField is an equality join, so it becomes a JOIN between the two tables on those columns. When it is followed by $unwind on the same field, the default behaviour drops documents with no match, which is an INNER JOIN; with preserveNullAndEmptyArrays: true it keeps them, which is a LEFT JOIN. A $lookup without $unwind returns the matches as an array, so the tool emits a LEFT JOIN and warns that SQL returns one row per match instead. Pipeline-form $lookup with let and pipeline is flagged for manual rewriting.
Why does $ne or $nin produce an extra IS NULL check?
In MongoDB, { status: { $ne: "closed" } } also matches documents where status is null or missing. In SQL, status <> 'closed' is unknown for NULL rows, so they would be silently excluded. To keep the results identical the converter emits (status <> 'closed' OR status IS NULL). The same applies to $nin and $not. If your column is NOT NULL you can delete the extra condition.
Can I run the converted SQL directly against my database?
Yes, once your MongoDB data has been migrated to tables whose column names match the document fields. Review the warnings first: operators such as $elemMatch, $size, $expr or $text have no portable SQL form and are left as clearly marked placeholders. Chat2DB is a free SQL client for PostgreSQL, MySQL, SQL Server, SQLite and MongoDB, so you can run both versions side by side and let its AI explain or tune the SQL — download it at https://chat2db.ai/download or open https://app.chat2db.ai in your browser.
