$fieldName
The short rule is: use $fieldName when you mean “the
value from this field” inside an expression. Do not use
$ when you are simply naming a field in a normal document
shape or filter key.
| Situation | Use | Example |
|---|---|---|
| Field name in a normal filter | No $ |
{ status: "paid" } |
| Operator name | Use $ |
{ totalAmount: { $gte: 1000 } } |
| Field reference inside aggregation expression | Use $ |
{ $sum: "$amount" } |
| Literal string value | No $ |
{ status: "paid" } |
// Filter key: no $ on field name
{ city: "Mumbai" }
// Operator: $ on the operator name
{ amount: { $gte: 500 } }
// Aggregation expression: $ means 'read from this field'
{ $project: { revenueWithTax: { $multiply: ["$revenue", 1.18] } } }
"$price" means “the
value inside the field named price.” "price" is just a
plain string.
| JSON | BSON |
|---|---|
| Text format | Binary format |
| Few basic types | Many rich types: ObjectId, Date, Int32, Int64, Decimal128, BinData |
| What you usually write | What MongoDB stores internally |
You usually write JSON-like documents in mongosh or application code. MongoDB converts them to BSON internally.
| Type | Use it for | Example |
|---|---|---|
| Int32 | Small whole numbers | NumberInt(42) |
| Int64 | Large whole numbers | NumberLong("9876543210") |
| Double | General numeric values | 3.14 |
| Decimal128 | Money and exact decimals | NumberDecimal("19.99") |
NumberDecimal for money. Do
not rely on floating-point doubles for financial values.
const session = client.startSession();
await session.withTransaction(async () => {
await orders.insertOne({ orderId: 1, customerId: 101 }, { session });
await inventory.updateOne(
{ productId: 22, available: { $gte: 1 } },
{ $inc: { available: -1 } },
{ session }
);
});
Backups are only trustworthy if you have tested restore.
// Logical backup mongodump --uri "mongodb://user:pass@host:27017/appdb" --out ./backup // Restore full dump mongorestore --uri "mongodb://user:pass@host:27017/appdb_restore" ./backup // Restore a specific namespace mongorestore --uri "mongodb://user:pass@host:27017/appdb_restore" --nsInclude="appdb.orders" ./backup
Create separate users for app access, backup, and admin work. Do not give applications admin roles unless there is a very specific reason.
// App user
use appdb
db.createUser({
user: "appUser",
pwd: passwordPrompt(),
roles: [{ role: "readWrite", db: "appdb" }]
})
// Backup operator
use admin
db.createUser({
user: "backupOperator",
pwd: passwordPrompt(),
roles: [
{ role: "backup", db: "admin" },
{ role: "restore", db: "admin" }
]
})
// Custom least-privilege role
use appdb
db.createRole({
role: "orderStatusEditor",
privileges: [
{
resource: { db: "appdb", collection: "orders" },
actions: ["find", "update"]
}
],
roles: []
})
$match early when the filter uses base collection
fields
$unwind only when you need array element-level work
$lookup after reduction when possible$group after the stream has the correct grain$sort, $limit, and final
$project near the end
db.orders.aggregate([
{ $match: { status: "paid" } },
{ $unwind: "$items" },
{
$lookup: {
from: "products",
localField: "items.productId",
foreignField: "_id",
as: "product"
}
},
{ $unwind: "$product" },
{
$group: {
_id: "$product.category",
revenue: { $sum: { $multiply: ["$items.qty", "$items.unitPrice"] } }
}
},
{ $sort: { revenue: -1 } },
{ $project: { _id: 0, category: "$_id", revenue: 1 } }
])
$facet when several summaries share the same
prepared input
db.orders.aggregate([
{ $match: { status: "paid" } },
{
$facet: {
byCity: [
{ $group: { _id: "$city", revenue: { $sum: "$totalAmount" } } }
],
byCategory: [
{ $unwind: "$items" },
{ $group: { _id: "$items.category", qty: { $sum: "$items.qty" } } }
]
}
}
])
Use GeoJSON and a 2dsphere index.
{
name: "Cafe A",
location: {
type: "Point",
coordinates: [77.5946, 12.9716] // longitude, latitude
}
}
db.places.createIndex({ location: "2dsphere" })
db.places.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [77.5946, 12.9716] },
$maxDistance: 2000
}
}
})
[longitude, latitude], not the other way around.
$jsonSchema for shape and type validation
// Validation
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["email", "name"],
properties: {
email: { bsonType: "string" },
name: { bsonType: "string" }
}
}
}
})
// Uniqueness
db.users.createIndex({ email: 1 }, { unique: true })