Conversation
📝 WalkthroughWalkthroughThe changes add MongoDB integration to a Next.js application by introducing a database utility module for client management and collection access, creating a new API route for retrieving collision data with configurable query limits, and updating project dependencies to support these additions. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @app/api/collisions/route.ts:
- Around line 1-16: The GET handler's limit parsing uses `parseInt(...) || 100`
which turns a valid 0 into 100 and hides parse errors; change the logic in `GET`
to parse `limitParam` with `Number.parseInt(limitParam ?? "100", 10)`, detect
NaN via `Number.isNaN(parsed)` and only use the 100 default when parsing fails,
then clamp the parsed value with `Math.max(0, Math.min(parsed, 1000))` (use 0 as
the minimum if you want to allow zero); add a try/catch around the DB calls (the
`getCollisionsCollection`, `collection.find(...).limit(limit).toArray()`
sequence) and return a controlled NextResponse with status 500 on error; finally
add a projection on the find (e.g. `collection.find({}, { projection: { _id: 0 }
})`) or map results to remove/transform `_id` before returning.
In @lib/mongodb.ts:
- Around line 62-66: getDb currently calls client.db(dbName) even when
process.env.MONGODB_DB is undefined, which can return an unintended default DB;
update getDb to explicitly validate that process.env.MONGODB_DB is set (e.g.,
const dbName = process.env.MONGODB_DB) and throw a clear error including the env
var name when it's missing before calling client.db(dbName); reference the getDb
function and clientPromise so the change is made in that function only.
- Around line 4-42: Remove the console.log statements that print the raw/uri
values (they leak secrets), call normalizeMongoUri on process.env.MONGODB_URI
and use the returned value for all subsequent validation and connection logic
(replace uses of the raw uri variable with the normalized value), and validate
the normalized URI with the existing startsWith checks (throw the same errors
but referencing the normalized value or its prefix snippet); ensure no sensitive
values are logged anywhere in this module.
In @package.json:
- Line 6: Add a Node engine constraint and a fallback dev script in
package.json: declare "engines.node" set to ">=20.19.0" to reflect
mongodb@^7.0.0 requirements and modify the scripts section to keep "dev" as
"doppler run -- next dev" while adding a new script name "dev:local" (or
"dev:plain") that runs "next dev" so developers can run locally without Doppler;
update package.json accordingly and, if desired, mention the Doppler requirement
in README.
🧹 Nitpick comments (1)
lib/mongodb.ts (1)
68-72: Align collection typing with Mongo documents (_id) or project it out.
db.collection<CollisionRecord>()implies returned docs matchtypes/collision.tsexactly, but Mongo will include_idunless you project it out in queries (or you model the document type asCollisionRecord & { _id: ... }).
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
bun.lockis excluded by!**/*.lockpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
app/api/collisions/route.tslib/mongodb.tspackage.json
🧰 Additional context used
🧬 Code graph analysis (2)
app/api/collisions/route.ts (1)
lib/mongodb.ts (1)
getCollisionsCollection(68-72)
lib/mongodb.ts (1)
types/collision.ts (1)
CollisionRecord(1-14)
| export const runtime = "nodejs"; | ||
| import { NextResponse } from "next/server"; | ||
| import { getCollisionsCollection } from "@/lib/mongodb"; | ||
|
|
||
| export async function GET(request: Request) { | ||
| const { searchParams } = new URL(request.url); | ||
| const limitParam = searchParams.get("limit"); | ||
| const limit = Math.max( | ||
| 1, | ||
| Math.min(Number.parseInt(limitParam ?? "100", 10) || 100, 1000) | ||
| ); | ||
| const collection = await getCollisionsCollection("collisions_2025"); | ||
| const data = await collection.find({}).limit(limit).toArray(); | ||
|
|
||
| return NextResponse.json({ data }); | ||
| } |
There was a problem hiding this comment.
Fix limit parsing (0 should not default to 100) + consider projection/error handling.
parseInt(...) || 100 treats 0 as invalid and returns 100. Also, consider projecting out _id (or mapping it) and returning a controlled error response on DB failures.
Proposed fix
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const limitParam = searchParams.get("limit");
- const limit = Math.max(
- 1,
- Math.min(Number.parseInt(limitParam ?? "100", 10) || 100, 1000)
- );
- const collection = await getCollisionsCollection("collisions_2025");
- const data = await collection.find({}).limit(limit).toArray();
-
- return NextResponse.json({ data });
+ const parsed = limitParam ? Number.parseInt(limitParam, 10) : NaN;
+ const limit = Math.max(1, Math.min(Number.isFinite(parsed) ? parsed : 100, 1000));
+
+ try {
+ const collection = await getCollisionsCollection();
+ const data = await collection
+ .find({}, { projection: { _id: 0 } })
+ .limit(limit)
+ .toArray();
+ return NextResponse.json({ data });
+ } catch (err) {
+ console.error("Failed to fetch collisions", err);
+ return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const runtime = "nodejs"; | |
| import { NextResponse } from "next/server"; | |
| import { getCollisionsCollection } from "@/lib/mongodb"; | |
| export async function GET(request: Request) { | |
| const { searchParams } = new URL(request.url); | |
| const limitParam = searchParams.get("limit"); | |
| const limit = Math.max( | |
| 1, | |
| Math.min(Number.parseInt(limitParam ?? "100", 10) || 100, 1000) | |
| ); | |
| const collection = await getCollisionsCollection("collisions_2025"); | |
| const data = await collection.find({}).limit(limit).toArray(); | |
| return NextResponse.json({ data }); | |
| } | |
| export const runtime = "nodejs"; | |
| import { NextResponse } from "next/server"; | |
| import { getCollisionsCollection } from "@/lib/mongodb"; | |
| export async function GET(request: Request) { | |
| const { searchParams } = new URL(request.url); | |
| const limitParam = searchParams.get("limit"); | |
| const parsed = limitParam ? Number.parseInt(limitParam, 10) : NaN; | |
| const limit = Math.max(1, Math.min(Number.isFinite(parsed) ? parsed : 100, 1000)); | |
| try { | |
| const collection = await getCollisionsCollection(); | |
| const data = await collection | |
| .find({}, { projection: { _id: 0 } }) | |
| .limit(limit) | |
| .toArray(); | |
| return NextResponse.json({ data }); | |
| } catch (err) { | |
| console.error("Failed to fetch collisions", err); | |
| return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); | |
| } | |
| } |
🤖 Prompt for AI Agents
In @app/api/collisions/route.ts around lines 1 - 16, The GET handler's limit
parsing uses `parseInt(...) || 100` which turns a valid 0 into 100 and hides
parse errors; change the logic in `GET` to parse `limitParam` with
`Number.parseInt(limitParam ?? "100", 10)`, detect NaN via
`Number.isNaN(parsed)` and only use the 100 default when parsing fails, then
clamp the parsed value with `Math.max(0, Math.min(parsed, 1000))` (use 0 as the
minimum if you want to allow zero); add a try/catch around the DB calls (the
`getCollisionsCollection`, `collection.find(...).limit(limit).toArray()`
sequence) and return a controlled NextResponse with status 500 on error; finally
add a projection on the find (e.g. `collection.find({}, { projection: { _id: 0 }
})`) or map results to remove/transform `_id` before returning.
| function normalizeMongoUri(raw: string | undefined) { | ||
| console.log("raw", raw); | ||
| if (!raw) return ""; | ||
| let value = raw.trim(); | ||
| // Strip surrounding quotes if present | ||
| if ( | ||
| (value.startsWith('"') && value.endsWith('"')) || | ||
| (value.startsWith("'") && value.endsWith("'")) | ||
| ) { | ||
| value = value.slice(1, -1); | ||
| } | ||
| // Remove accidental trailing semicolon | ||
| if (value.endsWith(";")) { | ||
| value = value.slice(0, -1); | ||
| } | ||
| // If there is stray punctuation right after the scheme (e.g., "mongodb+srv://;user") | ||
| // normalize it by removing non-alphanumeric chars immediately following "://" | ||
| value = value.replace( | ||
| /^(mongodb(?:\+srv)?:\/\/)\s*[^A-Za-z0-9]+/, | ||
| (_m, scheme) => `${scheme}` | ||
| ); | ||
| return value; | ||
| } | ||
|
|
||
| const uri = process.env.MONGODB_URI; | ||
| console.log("uri", uri); | ||
| if (!uri) { | ||
| throw new Error("❌ MONGODB_URI is not defined"); | ||
| } | ||
| console.log("uri.startsWith('mongodb://')", uri.startsWith("mongodb://")); | ||
| console.log("uri.startsWith('mongodb+srv://')", uri.startsWith("mongodb+srv://")); | ||
| if (!(uri.startsWith("mongodb://") || uri.startsWith("mongodb+srv://"))) { | ||
| throw new Error( | ||
| `❌ Invalid MONGODB_URI. It must start with "mongodb://" or "mongodb+srv://". Received prefix: ${uri.slice( | ||
| 0, | ||
| 20 | ||
| )}...` | ||
| ); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the lib/mongodb.ts file
find . -name "mongodb.ts" -type f 2>/dev/nullRepository: Lemirq/cision
Length of output: 73
🏁 Script executed:
# Check the size and content of lib/mongodb.ts
if [ -f "lib/mongodb.ts" ]; then
wc -l lib/mongodb.ts
fiRepository: Lemirq/cision
Length of output: 74
🏁 Script executed:
# Read the content of lib/mongodb.ts to verify the code state
if [ -f "lib/mongodb.ts" ]; then
cat -n lib/mongodb.ts
fiRepository: Lemirq/cision
Length of output: 2720
🌐 Web query:
mongodb driver v7 ObjectId JSON serialization toJSON() Next.js Route Handlers
💡 Result:
Short answer: convert ObjectId values to plain strings before returning them from Next.js Route Handlers (Next.js disallows objects with custom toJSON methods). Use ObjectId.toString() (or String(id)) when mapping documents, or serialize with a replacer/EJSON on the server — don’t rely on the driver’s toJSON behavior across versions.
Why + references:
- Next.js route handlers enforce JSON-serializable plain values and will error on objects with toJSON methods. [1]
- The MongoDB ObjectId exposes a toString() method to get the hex string. Use that to convert IDs. [2]
- Driver v7 ships with bson v7 (breaking changes possible), so behavior may differ vs older drivers — explicitly converting is safer. [3]
Minimal example for an app-route handler (Next.js):
- Map documents before returning:
const docs = await collection.find({}).toArray();
const out = docs.map(d => ({ ...d, _id: d._id.toString() }));
return new Response(JSON.stringify(out), { headers: { 'Content-Type': 'application/json' } });
Alternative approaches:
- Return only plain fields (e.g., replace _id with id string).
- Use a JSON replacer: JSON.stringify(doc, (k, v) => (v && v._bsontype === 'ObjectId' ? v.toString() : v));
- Use server-side EJSON serialization if you need to preserve BSON types and then decode client-side (but this adds complexity).
If you want, tell me your Next.js / mongodb package versions and I’ll give an exact snippet for your setup.
Sources:
[1] Next.js serialization / "Objects with toJSON methods are not supported".
[2] MongoDB docs: ObjectId.toString().
[3] MongoDB Node.js driver v7 docs / release notes.
🏁 Script executed:
# Search for all uses of normalizeMongoUri throughout the repo
rg "normalizeMongoUri" --type ts --type jsRepository: Lemirq/cision
Length of output: 125
Remove secret-leaking logs and apply normalizeMongoUri() before validation/connection.
The code logs raw and uri (which expose credentials) and validates the un-normalized URI directly, so quoted/semicolon URIs will fail even though the normalization function exists and should handle them.
Proposed fix
function normalizeMongoUri(raw: string | undefined) {
- console.log("raw", raw);
if (!raw) return "";
let value = raw.trim();
// Strip surrounding quotes if present
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
// Remove accidental trailing semicolon
if (value.endsWith(";")) {
value = value.slice(0, -1);
}
// If there is stray punctuation right after the scheme (e.g., "mongodb+srv://;user")
// normalize it by removing non-alphanumeric chars immediately following "://"
value = value.replace(
/^(mongodb(?:\+srv)?:\/\/)\s*[^A-Za-z0-9]+/,
(_m, scheme) => `${scheme}`
);
return value;
}
-const uri = process.env.MONGODB_URI;
-console.log("uri", uri);
+const uri = normalizeMongoUri(process.env.MONGODB_URI);
if (!uri) {
- throw new Error("❌ MONGODB_URI is not defined");
+ throw new Error("MONGODB_URI is not defined");
}
-console.log("uri.startsWith('mongodb://')", uri.startsWith("mongodb://"));
-console.log("uri.startsWith('mongodb+srv://')", uri.startsWith("mongodb+srv://"));
if (!(uri.startsWith("mongodb://") || uri.startsWith("mongodb+srv://"))) {
throw new Error(
- `❌ Invalid MONGODB_URI. It must start with "mongodb://" or "mongodb+srv://". Received prefix: ${uri.slice(
- 0,
- 20
- )}...`
+ 'Invalid MONGODB_URI. It must start with "mongodb://" or "mongodb+srv://".'
);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function normalizeMongoUri(raw: string | undefined) { | |
| console.log("raw", raw); | |
| if (!raw) return ""; | |
| let value = raw.trim(); | |
| // Strip surrounding quotes if present | |
| if ( | |
| (value.startsWith('"') && value.endsWith('"')) || | |
| (value.startsWith("'") && value.endsWith("'")) | |
| ) { | |
| value = value.slice(1, -1); | |
| } | |
| // Remove accidental trailing semicolon | |
| if (value.endsWith(";")) { | |
| value = value.slice(0, -1); | |
| } | |
| // If there is stray punctuation right after the scheme (e.g., "mongodb+srv://;user") | |
| // normalize it by removing non-alphanumeric chars immediately following "://" | |
| value = value.replace( | |
| /^(mongodb(?:\+srv)?:\/\/)\s*[^A-Za-z0-9]+/, | |
| (_m, scheme) => `${scheme}` | |
| ); | |
| return value; | |
| } | |
| const uri = process.env.MONGODB_URI; | |
| console.log("uri", uri); | |
| if (!uri) { | |
| throw new Error("❌ MONGODB_URI is not defined"); | |
| } | |
| console.log("uri.startsWith('mongodb://')", uri.startsWith("mongodb://")); | |
| console.log("uri.startsWith('mongodb+srv://')", uri.startsWith("mongodb+srv://")); | |
| if (!(uri.startsWith("mongodb://") || uri.startsWith("mongodb+srv://"))) { | |
| throw new Error( | |
| `❌ Invalid MONGODB_URI. It must start with "mongodb://" or "mongodb+srv://". Received prefix: ${uri.slice( | |
| 0, | |
| 20 | |
| )}...` | |
| ); | |
| } | |
| function normalizeMongoUri(raw: string | undefined) { | |
| if (!raw) return ""; | |
| let value = raw.trim(); | |
| // Strip surrounding quotes if present | |
| if ( | |
| (value.startsWith('"') && value.endsWith('"')) || | |
| (value.startsWith("'") && value.endsWith("'")) | |
| ) { | |
| value = value.slice(1, -1); | |
| } | |
| // Remove accidental trailing semicolon | |
| if (value.endsWith(";")) { | |
| value = value.slice(0, -1); | |
| } | |
| // If there is stray punctuation right after the scheme (e.g., "mongodb+srv://;user") | |
| // normalize it by removing non-alphanumeric chars immediately following "://" | |
| value = value.replace( | |
| /^(mongodb(?:\+srv)?:\/\/)\s*[^A-Za-z0-9]+/, | |
| (_m, scheme) => `${scheme}` | |
| ); | |
| return value; | |
| } | |
| const uri = normalizeMongoUri(process.env.MONGODB_URI); | |
| if (!uri) { | |
| throw new Error("MONGODB_URI is not defined"); | |
| } | |
| if (!(uri.startsWith("mongodb://") || uri.startsWith("mongodb+srv://"))) { | |
| throw new Error( | |
| 'Invalid MONGODB_URI. It must start with "mongodb://" or "mongodb+srv://".' | |
| ); | |
| } |
🤖 Prompt for AI Agents
In @lib/mongodb.ts around lines 4 - 42, Remove the console.log statements that
print the raw/uri values (they leak secrets), call normalizeMongoUri on
process.env.MONGODB_URI and use the returned value for all subsequent validation
and connection logic (replace uses of the raw uri variable with the normalized
value), and validate the normalized URI with the existing startsWith checks
(throw the same errors but referencing the normalized value or its prefix
snippet); ensure no sensitive values are logged anywhere in this module.
| export async function getDb() { | ||
| const client = await clientPromise; | ||
| const dbName = process.env.MONGODB_DB; | ||
| return client.db(dbName); | ||
| } |
There was a problem hiding this comment.
Handle missing MONGODB_DB explicitly (avoid accidentally using the wrong database).
client.db(dbName) with dbName === undefined can silently select an unintended default DB.
Proposed fix (pick one behavior)
export async function getDb() {
const client = await clientPromise;
- const dbName = process.env.MONGODB_DB;
- return client.db(dbName);
+ const dbName = process.env.MONGODB_DB?.trim();
+ // Option A (strict): require explicit DB name
+ // if (!dbName) throw new Error("MONGODB_DB is not defined");
+ // return client.db(dbName);
+
+ // Option B (flexible): fall back to default DB from URI
+ return dbName ? client.db(dbName) : client.db();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export async function getDb() { | |
| const client = await clientPromise; | |
| const dbName = process.env.MONGODB_DB; | |
| return client.db(dbName); | |
| } | |
| export async function getDb() { | |
| const client = await clientPromise; | |
| const dbName = process.env.MONGODB_DB?.trim(); | |
| // Option A (strict): require explicit DB name | |
| // if (!dbName) throw new Error("MONGODB_DB is not defined"); | |
| // return client.db(dbName); | |
| // Option B (flexible): fall back to default DB from URI | |
| return dbName ? client.db(dbName) : client.db(); | |
| } |
🤖 Prompt for AI Agents
In @lib/mongodb.ts around lines 62 - 66, getDb currently calls client.db(dbName)
even when process.env.MONGODB_DB is undefined, which can return an unintended
default DB; update getDb to explicitly validate that process.env.MONGODB_DB is
set (e.g., const dbName = process.env.MONGODB_DB) and throw a clear error
including the env var name when it's missing before calling client.db(dbName);
reference the getDb function and clientPromise so the change is made in that
function only.
| "private": true, | ||
| "scripts": { | ||
| "dev": "next dev", | ||
| "dev": "doppler run -- next dev", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check package.json for Node version, Next.js version, and MongoDB version
cat package.jsonRepository: Lemirq/cision
Length of output: 1191
🏁 Script executed:
# Check for .nvmrc file
if [ -f .nvmrc ]; then cat .nvmrc; else echo "No .nvmrc file found"; fiRepository: Lemirq/cision
Length of output: 77
🌐 Web query:
MongoDB Node.js driver v7 Node.js version requirements compatibility
💡 Result:
Short answer: MongoDB Node.js driver v7 requires Node.js >= 20.19.0 (minimum support); older Node.js versions are not supported. The v7 release also updates TypeScript target to ES2023 and bumps related peer-dependencies. [1][2]
Sources:
- Release notes for driver v7 (minimum Node.js v20.19.0, peer-dep changes). [1]
- MongoDB Node.js driver compatibility docs. [2]
Add Node.js engine constraint and fallback dev script.
mongodb@^7.0.0 requires Node.js ≥ 20.19.0, but the repo does not document this in engines.node—add it to prevent mismatched local/CI builds. Additionally, npm run dev hard-requires Doppler with no fallback; add a dev:plain or dev:local script pointing to next dev for local development without Doppler, or document the Doppler setup requirement clearly.
Suggested fix:
{
"engines": {
"node": ">=20.19.0"
},
"scripts": {
"dev": "doppler run -- next dev",
"dev:local": "next dev"
}
}🤖 Prompt for AI Agents
In @package.json at line 6, Add a Node engine constraint and a fallback dev
script in package.json: declare "engines.node" set to ">=20.19.0" to reflect
mongodb@^7.0.0 requirements and modify the scripts section to keep "dev" as
"doppler run -- next dev" while adding a new script name "dev:local" (or
"dev:plain") that runs "next dev" so developers can run locally without Doppler;
update package.json accordingly and, if desired, mention the Doppler requirement
in README.
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.