How to convert csv to json for mongodb import
- Step 1Export the collection data as CSV — From a spreadsheet, a SQL
SELECT … INTO OUTFILE, or an app export, save a CSV with a header row. The headers become Mongo document field names, so name them as your schema expects (createdAt, notCreated At, if your paths are camelCase). - Step 2Drop the CSV onto the converter above — Accepts
.csv,.tsv,.txt. PapaParse auto-detects the delimiter and handles RFC-4180 quoted fields, so commas and newlines inside quoted cells stay inside their cell. - Step 3Pick array for --jsonArray, or NDJSON for line mode — Array of objects → import with
mongoimport --jsonArray. NDJSON / JSON Lines → import with plainmongoimport(no flag) or use it in a Mongoose seed that reads line by line. Atlas's Compass import accepts both shapes. - Step 4Decide on type inference for _id and numeric IDs — Keep inference on so
age,price, and flags become typed. Turn it off if you have an_idor account number with leading zeros you must preserve — inference would turn007into7. - Step 5Set the indent (cosmetic for array mode) — For
mongoimportthe indent does not matter — pick Minified for a compact file or 2 spaces to eyeball it first. NDJSON is always one compact object per line regardless of indent. - Step 6Download, then import or seed — Download JSON (or NDJSON), then run
mongoimport --uri … --collection users --file users.json --jsonArray, orrequire()the file in a MongooseModel.insertMany(...)seed. Check the Records stat equals your expected document count.
Output mode → mongoimport command
How each output mode maps to a MongoDB ingestion path. The tool does not run mongoimport — it produces the file you feed to it.
| Output mode | File shape | Import command |
|---|---|---|
| Array of objects | [ {…}, {…} ] | mongoimport --collection c --file data.json --jsonArray |
| NDJSON / JSON Lines | one object per line | mongoimport --collection c --file data.ndjson (no flag) |
| Array of objects | [ {…}, {…} ] | Mongoose: Model.insertMany(require('./data.json')) |
| Grouped by column | { "key": [ {…} ] } | Not an import shape — for building a per-key document, transform after |
Type inference vs Mongoose schema expectations
What inference produces, and the BSON type Mongo stores. Inference is global (one toggle for the whole file).
| CSV cell | Inference on → JSON | Stored in Mongo as | Watch out |
|---|---|---|---|
36 | 36 | Int32 / Double | Matches a Number schema path |
true | true | Boolean | Matches a Boolean path |
null | null | Null | Field present, value null |
007 (account id) | 7 | Number | Leading zero lost — turn inference off |
9007199254740993 | "9007…" | String | Beyond safe-int → kept as string, not corrupted |
2026-06-12 | "2026-06-12" | String | Dates stay strings; cast in your schema / aggregation |
| `` (empty) | "" or key omitted | String / absent | Skip empty cells omits the field |
Cookbook
CSV-to-JSON recipes aimed at mongoimport and Mongoose seeds. Field values are illustrative.
Typed array for mongoimport --jsonArray
ExampleDefault settings produce a typed array. age is a number and active a boolean, so a Mongoose schema with those paths casts cleanly on insert.
Input (users.csv):
name,age,active
Ada,36,true
Linus,54,false
Output (array, inference on):
[
{ "name": "Ada", "age": 36, "active": true },
{ "name": "Linus", "age": 54, "active": false }
]
mongoimport --db app --collection users \
--file users.json --jsonArrayNDJSON for plain mongoimport
ExampleSwitch to NDJSON when you want the line-delimited form mongoimport reads with no flag — easier to stream for a large collection.
Input:
name,age
Ada,36
Linus,54
Output (NDJSON):
{"name":"Ada","age":36}
{"name":"Linus","age":54}
mongoimport --db app --collection users --file users.ndjsonKeep _id as a string so leading zeros survive
ExampleAn external account ID 00042 must stay verbatim. Turn inference off so every value, including the id, is a string.
Input:
_id,name
00042,Ada
00043,Linus
Output (inference OFF):
[
{ "_id": "00042", "name": "Ada" },
{ "_id": "00043", "name": "Linus" }
]Comma inside a description survives
ExampleQuote-aware parsing keeps the comma inside the quoted bio cell, so the document has one field, not two — the failure mode of importing the CSV directly.
Input (note the quoted field):
name,bio
Ada,"Mathematician, writer, and analyst"
Output:
[
{ "name": "Ada", "bio": "Mathematician, writer, and analyst" }
]Mongoose seed file
ExampleUse the downloaded array directly in an insertMany seed. Typed values mean no manual casting.
// seed.js
const data = require('./users.json'); // the array from this tool
await User.insertMany(data);
// data[0].age === 36 (number), data[0].active === true (boolean)Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Account / order ID loses leading zeros
By designWith inference on, 00042 becomes 42. For an _id or external reference that must round-trip exactly, turn off Infer numbers, booleans, null so every field, including the id, is a string. There is no per-column toggle — if only the id column is affected and you need the others typed, convert with inference off and cast the numeric fields in your Mongoose schema.
Big numeric ID stays a string instead of a corrupted number
PreservedAn ID beyond JavaScript's safe-integer range is left as a string by inference (it checks Number.isSafeInteger). This is the safe outcome — Mongo would otherwise have to store a rounded Double. If you genuinely need a BSON Long, import it as a string and cast in an aggregation, or use --columnsHaveTypes in mongoimport on the CSV path instead.
Date column imports as a string
Expected2026-06-12 and other date formats do not match the number/boolean/null patterns, so they stay strings. Mongo stores them as strings, not BSON Date. Cast on import with $dateFromString in an aggregation, or set the Mongoose path to Date and let casting convert the ISO string on insert.
Dotted header does not become a subdocument
Not supported hereA header address.city becomes a top-level field literally named address.city, not a nested { address: { city } }. mongoimport's CSV path interprets dotted headers as nesting; this JSON converter does not. To get subdocuments, convert here then run the array through json-unflattener to expand dotted keys into nested objects.
Duplicate field name collapses
OverwriteTwo columns named email map to one JSON key; the later one wins and the earlier value is lost. BSON documents cannot have duplicate field names, so this is unavoidable in the JSON. Rename one column before converting so both values land in distinct fields.
Empty cell stored as empty string, not missing
ExpectedBy default a blank cell becomes "", so the field exists with an empty value — different from the field being absent. If you want optional fields to be omitted (so Mongo treats them as unset), turn on Skip empty cells; then blank cells drop the field from that document.
Free tier row/file cap on a large collection
LimitFree tier caps at 2 MB / 500 rows. A real collection export usually needs Pro (100 MB / 100,000 rows) or Developer (5 GB, no row cap). For a one-off seed, split the CSV into chunks under the cap, convert each to NDJSON, and cat them together before mongoimport.
Grouped output is not an import shape
Not for importGrouped mode produces { "key": [ … ] }, which mongoimport will not read as a set of documents. Use it only when you actually want one keyed object (e.g. to build a lookup map). For seeding documents, use Array or NDJSON.
Frequently asked questions
Should I use mongoimport's CSV mode or convert to JSON first?
Convert to JSON first when types matter or your data has commas/newlines inside cells. mongoimport's --type csv stores everything as strings unless you maintain a --columnsHaveTypes spec, and unquoted commas shift columns. JSON with inference on gives Mongo real numbers and booleans, and quote-aware parsing keeps embedded commas inside their field.
Array or NDJSON for mongoimport?
Use Array output with mongoimport --jsonArray, or NDJSON with plain mongoimport (no flag). NDJSON is friendlier for very large collections because each line is an independent record you can stream. Functionally both import the same documents.
How do I keep an _id with leading zeros from becoming a number?
Turn off type inference. With it off, every value — including _id — is emitted as a string, so 00042 stays "00042". The trade-off is that numeric fields like age also become strings; let your Mongoose schema's Number path cast them on insert, or pre-split the file.
Will my date columns import as BSON Date?
No. Dates stay JSON strings because they do not match the numeric/boolean/null inference patterns. To store them as BSON Date, set the Mongoose schema path to Date (Mongoose casts ISO strings on insert), or convert with $dateFromString in an aggregation after a mongoimport.
Can it create subdocuments from dotted column names?
Not directly — address.city becomes a literal top-level field named address.city. To build nested subdocuments, convert here, then run the array through json-unflattener, which turns dotted keys into nested objects ready for Mongo.
Is my collection data uploaded to a server?
No. PapaParse parses the CSV in your browser and the JSON is generated client-side. Document data never reaches a JAD Apps server. Only an anonymous run counter is stored when you are signed in, and you can opt out.
How big a CSV can I convert for a seed or import?
Free: 2 MB / 500 rows. Pro: 100 MB / 100,000 rows. Pro+Media: 500 MB / 500,000 rows. Developer: 5 GB, no row cap. For larger collections, split the CSV into chunks under your cap, convert each to NDJSON, and concatenate the files.
Why did a row with an embedded newline not break my import?
Because the converter uses a quote-aware parser. A newline inside a quoted field (RFC 4180) stays part of that field's value, so the JSON has one record with a multi-line string — not two broken records. This is one of the main reasons to convert to JSON rather than feed raw CSV to mongoimport.
Can I turn this into a JSON Schema or TypeScript model for the collection?
Not in this tool, but the output feeds the right siblings: run the JSON through json-schema-generator for a JSON Schema, or json-to-typescript for an interface to type your Mongoose model and queries.
What happens to an empty cell — missing field or empty string?
By default it becomes an empty string "", so the field is present. Turn on Skip empty cells to omit the field entirely for that document, which is usually what you want for optional Mongo fields so they read as unset.
Can I go the other way — export a collection back to CSV?
Yes, with the sibling json-to-csv tool. Export the collection as a JSON array (e.g. mongoexport --jsonArray), then convert it back to a flat CSV for a spreadsheet or report.
Can I automate the conversion before a scheduled import?
Yes. Pair the @jadapps/runner once and POST the CSV to 127.0.0.1:9789/v1/tools/csv-to-json/run. A typical pipeline: nightly CSV export → runner converts to NDJSON → mongoimport into a staging collection. The data runs on your machine and never reaches JAD's servers.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.