Write concern says how many members must confirm a write; read preference says which member a read may go to. w: 1 means the primary alone acknowledged, so if it crashes before a secondary copies the entry the write is rolled back when the node rejoins — acknowledged, then gone. w: "majority" is the driver default and the only setting that survives an election.
await orders.insertOne({ _id: 'w1' }, { writeConcern: { w: 'majority' } });
try {
await orders.insertOne({ _id: 'w2' }, { writeConcern: { w: 2, wtimeoutMS: 1500 } });
} catch (e) { console.log('w:2 ->', e.constructor.name, e.code, e.codeName); }
console.log('documents now ->', await orders.countDocuments());
const db2 = client.db('shop', { readPreference: new ReadPreference('secondary') });
try { await db2.collection('wc').findOne({}); }
catch (e) { console.log('secondary ->', e.constructor.name); }w:2 -> MongoWriteConcernError 100 UnsatisfiableWriteConcern documents now -> 2 secondary -> MongoServerSelectionError
Read the second line twice. The w: 2 insert threw, and the document is still there — the count is 2, not 1. A MongoWriteConcernError means the write was applied and only the acknowledgement could not be met; retrying blindly after one is how duplicates appear. Asking for secondary where none exists is not an empty result but MongoServerSelectionError after serverSelectionTimeoutMS, which maxTimeMS cannot shorten because no server is ever reached.
The other modes are primary (the default, and what anything read after writing needs), primaryPreferred, secondaryPreferred and nearest; all but primary accept tag sets and maxStalenessSeconds, which drops a lagging member. Read concern is a third setting: local may return writes that later roll back, majority only majority-committed data. Set all three on the connection string, and wrap a write and the read that follows it in a session with causalConsistency: true.