Every command used across Lectures 11–20, with the dataset they were taught on. Search it during the lab instead of scrolling the notes.
Multi-word search is an AND. Typing index sort shows only rows containing both. Press Esc to clear.
mongosh "mongodb+srv://<user>:<pass>@cluster0.xxxxx.mongodb.net/"
mongoimport --uri "<connection-string>" --db bdma --collection rides --file data/uber_bookings.json --jsonArray --drop
--jsonArray is required because the file is one JSON array; --drop makes the import repeatable.use bdma
show dbs show collections
db.rides.countDocuments()
estimatedDocumentCount() when verifying a load.db.rides.findOne()
db.rides.drop()
mongoimport afterwards.db.rides.find({ status: "Completed" })
mongosh prints the first 20 and waits for it.db.rides.find({ status: "Completed" }, { booking_id: 1, booking_value: 1, _id: 0 })
_id is returned unless you explicitly suppress it.db.rides.find({ "route.pickup": "Connaught Place" })
db.rides.find({ booking_value: { $gt: 500 } })
$gt $gte $lt $lte $ne. Documents missing booking_value never match a $gt.db.rides.find({ vehicle_type: { $in: ["Uber XL", "Premier Sedan"] } })
$nin is the negation.db.rides.find({ status: "Completed", booking_value: { $gt: 800 } })
db.rides.find({ $or: [{ status: "Cancelled by Driver" }, { status: "No Driver Found" }] })
$and, $nor and $not follow the same shape.db.rides.find({ ratings: { $exists: false } })
ratings, booking_value and payment_method are absent on non-completed bookings — absence carries meaning.db.rides.find({ "cancellation.reason": { $regex: /AC/i } })
/^AC/ when you can.db.rides.find().sort({ booking_value: -1 }).limit(10)
-1 descending, 1 ascending.db.rides.find().skip(20).limit(10)
skip() degrades on large offsets because the server still walks the skipped documents — range queries scale better.db.rides.distinct("vehicle_type")
db.rides.countDocuments({ status: "Cancelled by Driver" })
db.rides.insertOne({ booking_id: "CNR999001", status: "Completed", booking_value: 250 })
_id if you omit it.db.rides.insertMany([{ ... }, { ... }])
{ ordered: false } to continue past individual failures.db.rides.updateOne({ booking_id: "CNR3000142" }, { $set: { payment_method: "UPI" } })
$set creates the field if it is missing. Forgetting $set and passing a bare object replaces the whole document.db.rides.updateMany({ status: "Incomplete" }, { $set: { review_flag: true } })
countDocuments() first.db.rides.updateOne({ booking_id: "CNR3000142" }, { $inc: { booking_value: 50 } })
$mul, $min and $max work the same way.db.rides.updateMany({}, { $unset: { review_flag: "" } })
$unset is ignored.db.rides.updateOne({ booking_id: "X" }, { $set: { status: "Completed" } }, { upsert: true })
db.rides.deleteMany({ status: "Incomplete" })
deleteMany({}) empties the collection but keeps the indexes.db.rides.createIndex({ status: 1 })
db.rides.createIndex({ status: 1, booking_value: -1 })
db.rides.createIndex({ booking_id: 1 }, { unique: true })
db.rides.createIndex({ booking_value: 1 }, { partialFilterExpression: { status: "Completed" } })
db.rides.createIndex({ "cancellation.reason": "text" })
db.rides.getIndexes()
_id_ is always present and cannot be dropped.db.rides.dropIndex("status_1")
db.rides.find({ status: "Completed" }).explain("executionStats")
totalDocsExamined with nReturned — if docs examined is far larger, the index is not doing its job.db.rides.find({ ... }).explain("executionStats").executionStats.executionTimeMillis
COLLSCAN vs IXSCAN
stage in an explain plan. COLLSCAN reads every document; IXSCAN walks an index. Seeing COLLSCAN on a large collection is the signal to add an index.db.rides.aggregate([...], { explain: true })
$match and $sort were pushed down to an index.db.rides.aggregate([{ $match: { status: "Completed" } }])
$match first. It is the only stage that can use an index, and it shrinks everything downstream.{ $group: { _id: "$vehicle_type", revenue: { $sum: "$booking_value" }, n: { $sum: 1 } } }
_id is the grouping key; { $sum: 1 } counts documents.{ $group: { _id: null, total: { $sum: "$booking_value" } } }
_id: null collapses everything into one bucket — a grand total across the collection.{ $group: { _id: "$status", avg: { $avg: "$booking_value" }, max: { $max: "$booking_value" } } }
$avg $min $max $first $last $push $addToSet are the accumulators. $avg silently skips missing fields.{ $sort: { revenue: -1 } } { $limit: 10 }
$limit straight after $sort lets the server use a bounded top-K sort.{ $project: { _id: 0, vehicle: "$_id", revenue: { $round: ["$revenue", 2] } } }
$round makes the result presentable.{ $match: { bookings: { $gte: 1000 } } }
$group to drop thin buckets before ranking by a rate — otherwise 03:00, with 46 bookings, tops the failure-rate chart on noise alone.{ $addFields: { hour: { $toInt: { $substr: ["$booked_at", 11, 2] } } } }
booked_at is stored as a string in this dataset, so we slice it rather than use a date operator.{ $addFields: { ts: { $toDate: "$booked_at" } } }
$year/$month/$hour operators become available.{ $dateFromString: { dateString: "$booked_at" } }
format and onError options for messy input.{ $cond: [{ $eq: ["$status", "Completed"] }, 1, 0] }
$sum to count a subset inside a group — this is how a completion rate is computed in one pass.{ $ifNull: ["$booking_value", 0] }
booking_value.{ $unwind: "$tags" }
$match before it.{ $lookup: { from: "drivers", localField: "driver_id", foreignField: "_id", as: "driver" } }
{ $facet: { byStatus: [...], byHour: [...] } }
{ $out: "rides_summary" }
$merge is the incremental version and must be the last stage.docker run -d --name bdma-redis -p 6379:6379 redis:7-alpine
docker stop bdma-redis and docker rm bdma-redis to clean up.redis-cli redis-cli -h host -p 6379 -a password
PING should answer PONG.SET dash:total:bookings 15000 GET dash:total:bookings
INCR dash:total:bookings INCRBY dash:status:Completed 5
INCRBYFLOAT dash:revenue:2024-03-14 412.50
MGET dash:status:Completed dash:status:Incomplete
EXPIRE dash:session:abc 3600 TTL dash:session:abc
TTL returns -1 for no expiry, -2 if the key is gone.SETEX cache:report 300 "{...}"
SCAN 0 MATCH "dash:*" COUNT 100
KEYS *. KEYS blocks the single-threaded server across the whole keyspace; SCAN iterates in cursored batches.DEL key EXISTS key TYPE key
TYPE is how you find out that a key you thought was a string is actually a hash.FLUSHDB
HSET dash:payment UPI 4613 Cash 2593 HGETALL dash:payment
HINCRBY dash:payment UPI 1
LPUSH rides:recent "CNR3000142" LRANGE rides:recent 0 9
LTRIM rides:recent 0 99 to cap it at 100 entries.SADD rides:customers:2024-03-14 "CID482910" SCARD rides:customers:2024-03-14
SINTER rides:customers:2024-03-14 rides:customers:2024-03-15
SUNION and SDIFF complete the algebra.ZADD dash:vehicle:revenue 536854 "Premier Sedan"
ZINCRBY dash:vehicle:revenue 412.5 "Go Sedan"
ZREVRANGE dash:vehicle:revenue 0 4 WITHSCORES
ZRANK dash:vehicle:revenue "Uber XL" ZSCORE dash:vehicle:revenue "Uber XL"
SETBIT dash:actives:2024-03-14 482910 1
BITCOUNT dash:actives:2024-03-14
BITOP AND dash:retained dash:actives:2024-03-14 dash:actives:2024-03-15
AND the two days, then BITCOUNT the result. OR, XOR and NOT are also available.PFADD dash:uniques:2024-03-14 "CID482910" PFCOUNT dash:uniques:2024-03-14
PFMERGE dash:uniques:week dash:uniques:2024-03-14 dash:uniques:2024-03-15
MULTI … EXEC
DISCARD abandons the queue.WATCH key
EXEC fails if the watched key changed in the meantime.INFO memory INFO stats
used_memory_human and keyspace_hits vs keyspace_misses are the two numbers that matter for a cache.MEMORY USAGE dash:actives:2024-03-14
CONFIG SET maxmemory-policy allkeys-lru
allkeys-lru for a cache, volatile-lru to evict only keys with a TTL, noeviction to fail writes instead of dropping data.BGSAVE LASTSAVE
MONITOR
npm install mongodb redis
const client = new MongoClient(uri); await client.connect();
await db.collection("rides").aggregate(pipeline).toArray()
mongosh.const redis = createClient({ url: "redis://localhost:6379" }); await redis.connect();
await redis.multi().incr("dash:total:bookings").hIncrBy("dash:payment", "UPI", 1).exec()
A note on destructive commands. db.rides.drop(), deleteMany({}) and FLUSHDB appear here because you will need them to reset your lab environment. Build the habit now of running the matching countDocuments() or SCAN first, so that in three years' time you do not run one against production.