Menu
CoddyTech

MongoDB CRUD Interview Questions

Changing data safely: update operators, upserts, the counts an update returns, array updates, bulk inserts and deletes.

10 questions
  1. What is the difference between updateOne, updateMany and replaceOne?

    updateOne changes the first matching document and updateMany every match; both take update operators such as $set, so fields you do not name stay. replaceOne swaps the whole document for a new one, keeping only _id: fields you leave out are gone. The driver refuses an update document without operators, which stops you from replacing a document by accident.

  2. Which update operators should you know?

    $set and $unset (add, change or remove a field), $inc and $mul (arithmetic), $min and $max (keep the smaller or larger value), $rename, $currentDate, and for arrays $push, $addToSet, $pull and $pop. One update can use several operators, and the whole update of one document is atomic. $inc on a missing field creates it.

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const items = client.db('shop').collection('items');
      await items.insertOne({ sku: 'pen', stock: 10, price: 20, promo: true });
      await items.updateOne(
        { sku: 'pen' },
        { $inc: { stock: -3, sold: 3 }, $min: { price: 15 }, $unset: { promo: '' } }
      );
      const pen = await items.findOne({ sku: 'pen' });
      console.log(pen.stock, pen.sold, pen.price, pen.promo);
    }
    main().finally(() => client.close());
  3. What is the difference between $push and $addToSet?

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const posts = client.db('blog').collection('posts');
      await posts.insertOne({ _id: 1, pushed: ['db'], added: ['db'] });
      for (const tag of ['db', 'node']) {
        await posts.updateOne({ _id: 1 }, { $push: { pushed: tag }, $addToSet: { added: tag } });
      }
      const post = await posts.findOne({ _id: 1 });
      console.log(post.pushed.join(','), '|', post.added.join(','));
    }
    main().finally(() => client.close());

    It prints db,db,node | db,node. $push always appends, so pushed gets a second db. $addToSet appends only values not already in the array, so added skips db and gains node. $addToSet does not remove duplicates that are already there. Both take $each to add several values, and $pull removes every element equal to a value.

  4. What does an upsert do when no document matches?

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const carts = client.db('shop').collection('carts');
      const update = { $inc: { items: 2 }, $setOnInsert: { createdBy: 'web' } };
      const first = await carts.updateOne({ user: 'asha' }, update, { upsert: true });
      const second = await carts.updateOne({ user: 'asha' }, update, { upsert: true });
      console.log(first.matchedCount, first.upsertedCount, second.matchedCount, second.modifiedCount);
      const cart = await carts.findOne({ user: 'asha' });
      console.log(cart.items, cart.createdBy);
    }
    main().finally(() => client.close());

    It prints 0 1 1 1 and 4 web. With upsert: true, no match means insert: MongoDB builds the document from the filter's equality fields (user: 'asha'), then applies the update, so items starts at 2. $setOnInsert fields are written only on that insert. The second call matches and modifies. Two concurrent upserts can both insert unless a unique index covers the filter field.

  5. What is the difference between matchedCount and modifiedCount?

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const users = client.db('shop').collection('users');
      await users.insertMany([
        { name: 'Asha', active: true },
        { name: 'Ravi', active: false },
        { name: 'Meera', active: true },
      ]);
      const result = await users.updateMany({}, { $set: { active: true } });
      console.log(result.matchedCount, result.modifiedCount);
    }
    main().finally(() => client.close());

    It prints 3 1. matchedCount counts the documents the filter selected; modifiedCount counts the ones that actually changed. Two users already had active: true, and MongoDB does not rewrite a document when the update would leave it the same. Check matchedCount to know a record exists, modifiedCount to know something changed.

  6. What does findOneAndUpdate return by default?

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const counters = client.db('shop').collection('counters');
      await counters.insertOne({ _id: 'order', seq: 41 });
      const a = await counters.findOneAndUpdate({ _id: 'order' }, { $inc: { seq: 1 } });
      const b = await counters.findOneAndUpdate(
        { _id: 'order' },
        { $inc: { seq: 1 } },
        { returnDocument: 'after' }
      );
      console.log(a.seq, b.seq);
    }
    main().finally(() => client.close());

    It prints 41 43. findOneAndUpdate finds, updates and returns one document atomically, and by default it returns the document as it was before the update; returnDocument: 'after' returns the new version. That atomicity is why it is the standard way to hand out sequence numbers: two callers never get the same value. Driver 6 returns the document itself; older drivers wrapped it in { value }.

  7. How do you update one element inside an array?

    With the positional operators. $ updates the first element the query matched (the array field must be in the filter), $[] updates every element, and $[name] with arrayFilters updates the elements that match a condition.

    // add 1 to the qty of the item with sku 'b'
    db.orders.updateOne({ _id: 1, 'items.sku': 'b' }, { $inc: { 'items.$.qty': 1 } })
    
    // mark every item as shipped
    db.orders.updateOne({ _id: 1 }, { $set: { 'items.$[].shipped': true } })
    
    // set qty to 0 for items cheaper than 5
    db.orders.updateOne(
      { _id: 1 },
      { $set: { 'items.$[cheap].qty': 0 } },
      { arrayFilters: [{ 'cheap.price': { $lt: 5 } }] }
    )
    
  8. How do you delete documents, and how is that different from drop?

    deleteOne(filter) removes the first match and deleteMany(filter) every match; both return deletedCount. deleteMany({}) empties a collection but keeps its indexes and options, while drop() removes the collection with its indexes and is much faster for clearing everything. Many apps soft delete instead (a deletedAt field), so records can be restored and audited.

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const logs = client.db('app').collection('logs');
      await logs.insertMany([{ level: 'info' }, { level: 'error' }, { level: 'info' }]);
      const one = await logs.deleteOne({ level: 'info' });
      const many = await logs.deleteMany({ level: 'info' });
      console.log(one.deletedCount, many.deletedCount, await logs.countDocuments());
    }
    main().finally(() => client.close());
  9. What happens when one document in insertMany fails?

    insertMany is ordered by default: it inserts in sequence and stops at the first error, so the documents before it stay inserted and the rest are skipped. With { ordered: false } the server tries every document and reports all failures together, which is also faster for bulk loads. Either way there is no rollback; use a transaction if the batch must be all or nothing.

    try {
      await users.insertMany(docs, { ordered: false });
    } catch (err) {
      // MongoBulkWriteError
      console.log(err.insertedCount, err.writeErrors.length);
    }
    
  10. What is the difference between countDocuments and estimatedDocumentCount?

    countDocuments(filter) counts matching documents by running a query: exact, can use an index, but costs a scan. estimatedDocumentCount() takes no filter and reads the total from collection metadata: instant, but it can be off after an unclean shutdown, and on a sharded cluster it can include orphaned documents. The old count() is deprecated in the drivers.

    Node.js
    const { MongoClient } = require('mongodb');
    const client = new MongoClient('mongodb://localhost:27017');
    
    async function main() {
      const orders = client.db('shop').collection('orders');
      await orders.insertMany([{ status: 'paid' }, { status: 'new' }, { status: 'paid' }]);
      console.log(await orders.countDocuments({ status: 'paid' }));
      console.log(await orders.estimatedDocumentCount());
    }
    main().finally(() => client.close());
Coddy programming languages illustration

Learn to code with Coddy

Get started