api-database-mongodb-72d9a0 — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited api-database-mongodb-72d9a0 (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Quick Guide: Use Mongoose as the ODM for MongoDB. Define schemas with automatic TypeScript inference, uselean()for read-only queries, prefer embedding over referencing for co-accessed data, place$matchearly in aggregation pipelines, and always define indexes to match your query patterns.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)(You MUST define Mongoose middleware (pre/post hooks) BEFORE calling `model()` -- hooks registered after model compilation are silently ignored)
(You MUST pass `{ session }` to EVERY operation inside a transaction -- missing session causes operations to run outside the transaction)
(You MUST use `.lean()` for read-only queries that send results directly to API responses -- skipping lean wastes 3x memory on hydration overhead)
(You MUST use `127.0.0.1` instead of `localhost` in connection strings -- Node.js 18+ prefers IPv6 and `localhost` can cause connection timeouts)
(You MUST NOT use `findOneAndUpdate` / `updateOne` and expect `save` middleware to fire -- only `save()` and `create()` trigger document middleware)
</critical_requirements>
Auto-detection: MongoDB, Mongoose, mongoose.connect, Schema, model, ObjectId, populate, aggregate, $match, $group, $lookup, lean, HydratedDocument, InferSchemaType, MongoClient, Atlas
When to use:
Key patterns covered:
When NOT to use:
Detailed Resources:
Core Patterns:
Query Patterns:
Aggregation:
Advanced Patterns:
Indexing:
<philosophy>
MongoDB is a document database. Mongoose provides schema-based modeling on top of it. The core principle: data that is accessed together should be stored together.
Core principles:
.lean() for read-only queries. It returns plain objects (3x less memory) instead of full Mongoose documents.When to use MongoDB / Mongoose:
</philosophy>
<patterns>
Establish a single connection at startup with named constants for pool/timeout config and environment variables for credentials. See examples/core.md for full examples including connection events and graceful shutdown.
const connection = await mongoose.connect(process.env.MONGODB_URI!, {
maxPoolSize: POOL_SIZE_MAX,
minPoolSize: POOL_SIZE_MIN,
serverSelectionTimeoutMS: SERVER_SELECTION_TIMEOUT_MS,
socketTimeoutMS: SOCKET_TIMEOUT_MS,
retryWrites: true,
retryReads: true,
});Let Mongoose infer types from the schema definition. Use explicit interfaces only when adding methods, statics, or virtuals. See examples/core.md for full typing examples with HydratedDocument, InferSchemaType, and generic parameters.
// Preferred: automatic type inference
const userSchema = new Schema(
{
name: { type: String, required: true, trim: true },
email: { type: String, required: true, unique: true, lowercase: true },
role: {
type: String,
enum: ["admin", "user", "moderator"] as const,
default: "user",
},
},
{ timestamps: true },
);
const User = model("User", userSchema);// For methods/statics/virtuals: explicit interfaces with Schema generics
const userSchema = new Schema<IUser, UserModel, IUserMethods, {}, IUserVirtuals>({ ... });Use .lean() for read-only queries, save() when middleware must fire, findByIdAndUpdate with { runValidators: true } for direct updates. See examples/core.md for full CRUD examples.
const user = await User.findById(id).lean(); // read-only, 3x less memory
await User.insertMany(users, { ordered: false }); // bulk insert
await User.findByIdAndUpdate(id, update, { new: true, runValidators: true }); // direct updateUse comparison/logical operators for filters, .populate() with field selection and limits. See examples/queries.md for dynamic query builders, cursor-based pagination, and populate patterns.
const post = await Post.findById(id)
.populate("author", "name email")
.populate({
path: "comments",
options: { sort: { createdAt: -1 }, limit: 10 },
})
.lean();Add custom error messages, regex validation, and array-level validators. See examples/core.md for complete validation examples.
price: {
type: Number,
required: true,
min: [0, "Price cannot be negative"],
validate: { validator: (v: number) => Number.isFinite(v), message: "Price must be finite" },
},
sku: {
type: String,
required: true,
unique: true,
match: [/^[A-Z]{2}-\d{6}$/, "SKU must match format XX-000000"],
},</patterns>
<red_flags>
High Priority Issues:
.lean() and expecting .save() to work -- lean returns plain objects without Mongoose methodsmodel() call -- hooks are silently ignoredPromise.all()) -- MongoDB does not support parallel operations within a single transactionlocalhost in connection strings on Node.js 18+ -- IPv6 preference causes connection timeouts, use 127.0.0.1{ session } on any operation inside a transaction -- that operation runs outside the transactionMedium Priority Issues:
findOneAndUpdate / updateOne and expecting pre('save') hooks to fire -- only save() and create() trigger document middleware.populate() without limit or field selection -- can return thousands of documents per queryrunValidators: true on findOneAndUpdate -- schema validation is skipped by default on updates$where or JavaScript expressions in queries -- disables indexes and enables injectionCommon Mistakes:
{ new: true } on findOneAndUpdate -- returns the old document by defaultSchema.Types.ObjectId in TypeScript interfaces instead of Types.ObjectId -- Schema.Types.ObjectId is for schema definitions, Types.ObjectId is for interfaces.lean() on write operations -- lean is for reads onlydoc.isNew in post('save') hooks -- always false after save, use this.$locals.wasNew set in a pre('save') hookGotchas & Edge Cases:
deleteOne / deleteMany do not trigger pre('remove') middleware -- use findOneAndDelete or document .deleteOne() if you need middlewaretoJSON() / toObject() by default -- set { toJSON: { virtuals: true } } in schema optionsremove() was completely removed in Mongoose 7+ -- use deleteOne() or deleteMany() insteadnext() in pre hooks -- use async/await insteadFilterQuery to QueryFilter -- update TypeScript imports if upgradingupdatePipeline: true for pipeline-style updates -- they throw by defaultbackground index option -- MongoDB 4.2+ builds all indexes in the background by default</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)(You MUST define Mongoose middleware (pre/post hooks) BEFORE calling `model()` -- hooks registered after model compilation are silently ignored)
(You MUST pass `{ session }` to EVERY operation inside a transaction -- missing session causes operations to run outside the transaction)
(You MUST use `.lean()` for read-only queries that send results directly to API responses -- skipping lean wastes 3x memory on hydration overhead)
(You MUST use `127.0.0.1` instead of `localhost` in connection strings -- Node.js 18+ prefers IPv6 and `localhost` can cause connection timeouts)
(You MUST NOT use `findOneAndUpdate` / `updateOne` and expect `save` middleware to fire -- only `save()` and `create()` trigger document middleware)
Failure to follow these rules will cause silent data corruption, middleware bypass, or transaction isolation failures.
</critical_reminders>
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.