liveBook · Manning

Data integrity

As explained in MongoDB 8.0 in Action, Third Edition

Data consistency is the property that stored data remains accurate, coherent, and compliant with defined integrity constraints.

Data integrity means keeping stored data coherent and protected from unintended changes. In MongoDB, the first safeguard is single-document atomicity: an insert, update, or delete of one document completes in full or does not take effect. When related changes span documents, a multidocument transaction can make them succeed or fail together. section 8.2 section 8.0

Avoid a partial booking

A travel booking needs both a flight and a hotel. If the flight reservation succeeds but the hotel reservation fails, aborting the transaction also undoes the flight reservation. The database is not left showing half a booking. section 8.0

Prefer storing related data together when the application permits it: single-document atomicity often avoids the need for a distributed transaction. When updates must cross documents, put all dependent operations in one transaction. For example, a transaction can update an account, update its customer record, and insert a transaction record; if an operation fails, the group is aborted. section 8.5 section 8.4.3

Listing 8.2 Executing a multidocument transaction with Node.js and Callback API
const { MongoClient } = require('mongodb')

// Replace with your actual connection string
const uri = "your_mongodb_connection_string"

async function run(accountId) {
  const client = new MongoClient(uri)

  try {
    await client.connect()
    const session = client.startSession()

    const transactionOptions = {
      readConcern: { level: 'snapshot' },
      writeConcern: { w: 'majority' },
      readPreference: 'primary'
    }

    await session.withTransaction(async () => {
      const accounts = client.db('sample_analytics').collection('accounts')
      const customers = client.db('sample_analytics').collection('customers')
      const transactions = client.db('sample_analytics').collection('transactions')
      const currentDate = new Date()

      const account = await accounts.findOne(
        { account_id: parseInt(accountId) },
        { session }
      )
      if (!account) throw new Error('Account not found')

      const accountsUpdateResult = await accounts.updateOne(
        { account_id: parseInt(accountId) },
        {
          $set: { limit: 12000, last_transaction_date: currentDate },
          $inc: { transaction_count: 1 }
        },
        { session }
      )

      const customersUpdateResult = await customers.updateMany(
        { accounts: { $in: [parseInt(accountId)] } },
        {
          $inc: { transaction_count: 1 },
          $set: { last_transaction_date: currentDate }
        },
        { session }
      )

      const transactionsInsertResult = await transactions.insertOne(
        {
          account_id: parseInt(accountId),
          transaction_count: account.transaction_count + 1,
          bucket_start_date: currentDate,
          bucket_end_date: currentDate,
          transactions: [
            {
              date: currentDate,
              amount: 1500,
              transaction_code: 'buy',
              symbol: 'amzn',
              price: '125.00',
              total: '187500.00'
            }
          ]
        },
        { session }
      )

      console.log("Transaction committed.")
      console.log("Accounts updated:", accountsUpdateResult.modifiedCount)
      console.log("Customers updated:", customersUpdateResult.modifiedCount)
      console.log("New transaction inserted:", transactionsInsertResult.insertedId)

    }, transactionOptions)

    session.endSession()
  } catch (error) {
    console.error("Transaction aborted due to error:", error)
  } finally {
    await client.close()
  }
}

// Get accountId from command line arguments
const accountId = process.argv[2]
if (!accountId) {
  console.error("Please provide an account ID as an argument.")
  process.exit(1)
}

run(accountId).catch(console.dir)

The Node.js listing shows dependent account, customer, and transaction operations inside a session’s withTransaction callback, with transaction read and write concerns configured. section 8.4.3

Keep the integrity mechanism practical to operate:

  • Keep transactions short, use indexes for their operations, and configure appropriate read and write concerns. Handle transient failures with retries; transactions across shards add performance overhead. section 8.5
  • Maintain backups separately from Atlas Online Archive. Archived data remains queryable, but the archive is not a recovery substitute for data loss or corruption. section 17.0
  • Protect against changes made without permission through security controls. Atlas SQL takes a different, narrower approach: its federated interface is read-only, avoiding writes and synchronization across queried sources. section 20.0 section 18.1

How MongoDB 8.0 in Action, Third Edition covers it

How deep it goes
Explains single-document atomicity, demonstrates multidocument transactions, and gives operational cautions; does not develop a general integrity-constraint specification.
Examples
Uses a flight-and-hotel booking rollback and a Node.js transaction updating accounts, customers, and transaction records.
What it assumes
Starts from single-document atomicity; provides Node.js installation, driver installation, and connection-string steps for the transaction example.
What you can do after
Apply it via the MongoDB Node.js Driver’s withTransaction method to group dependent updates and handle failures.
How it connects
Connects atomicity, ACID transactions, data modeling, backups, security, and read-only federated queries.

Also explained in

Compare how 18 books explain data integrity →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of MongoDB 8.0 in Action, Third Edition. The section links point to the parts of the book it draws on.