Skip to content

Commit fb6210f

Browse files
authored
fix(shell-api): handle coll.stats() in sharded clusters MONGOSH-731 (#817)
`result.shards` is an object in sharded clusters, so it is never an iterable. `result.shards` is also a (non-empty object) in sharded clusters for unsharded collections. Therefore, just always iterate over all entries in the object here.
1 parent 8548f05 commit fb6210f

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

packages/shell-api/src/collection.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,10 +1418,8 @@ export default class Collection extends ShellApiClass {
14181418
};
14191419
updateStats(result);
14201420

1421-
if (result.sharded) {
1422-
for (const shardName of result.shards) {
1423-
updateStats(result.shards[shardName]);
1424-
}
1421+
for (const shardName of Object.keys(result.shards ?? {})) {
1422+
updateStats(result.shards[shardName]);
14251423
}
14261424
return result;
14271425
}

packages/shell-api/src/shard.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,64 @@ describe('Shard', () => {
13131313
}
13141314
});
13151315
});
1316+
describe('collection.stats()', () => {
1317+
let db: Database;
1318+
let hasTotalSize: boolean;
1319+
const dbName = 'shard-stats-test';
1320+
const ns = `${dbName}.test`;
1321+
1322+
beforeEach(async() => {
1323+
db = sh._database.getSiblingDB(dbName);
1324+
await db.getCollection('test').insertOne({ key: 1 });
1325+
await db.getCollection('test').createIndex({ key: 1 });
1326+
hasTotalSize = !(await db.version()).match(/^4\.[0123]\./);
1327+
});
1328+
afterEach(async() => {
1329+
await db.dropDatabase();
1330+
});
1331+
context('unsharded collections', () => {
1332+
it('works without indexDetails', async() => {
1333+
const result = await db.getCollection('test').stats();
1334+
expect(result.sharded).to.equal(false);
1335+
expect(result.count).to.equal(1);
1336+
if (hasTotalSize) {
1337+
expect(result.shards[result.primary].totalSize).to.be.a('number');
1338+
}
1339+
expect(result.shards[result.primary].indexDetails).to.equal(undefined);
1340+
});
1341+
it('works with indexDetails', async() => {
1342+
const result = await db.getCollection('test').stats({ indexDetails: true });
1343+
expect(result.shards[result.primary].indexDetails._id_.metadata.formatVersion).to.be.a('number');
1344+
});
1345+
});
1346+
context('sharded collections', () => {
1347+
beforeEach(async() => {
1348+
expect((await sh.enableSharding(dbName)).ok).to.equal(1);
1349+
expect((await sh.shardCollection(ns, { key: 1 })).collectionsharded).to.equal(ns);
1350+
});
1351+
it('works without indexDetails', async() => {
1352+
const result = await db.getCollection('test').stats();
1353+
expect(result.sharded).to.equal(true);
1354+
expect(result.count).to.equal(1);
1355+
expect(result.primary).to.equal(undefined);
1356+
for (const shard of Object.values(result.shards) as any[]) {
1357+
if (hasTotalSize) {
1358+
expect(shard.totalSize).to.be.a('number');
1359+
}
1360+
expect(shard.indexDetails).to.equal(undefined);
1361+
}
1362+
});
1363+
it('works with indexDetails', async() => {
1364+
const result = await db.getCollection('test').stats({ indexDetails: true });
1365+
for (const shard of Object.values(result.shards) as any[]) {
1366+
if (hasTotalSize) {
1367+
expect(shard.totalSize).to.be.a('number');
1368+
}
1369+
expect(shard.indexDetails._id_.metadata.formatVersion).to.be.a('number');
1370+
}
1371+
});
1372+
});
1373+
});
13161374
describe('collection.isCapped', () => {
13171375
it('returns true for config.changelog', async() => {
13181376
const ret = await sh._database.getSiblingDB('config').getCollection('changelog').isCapped();

0 commit comments

Comments
 (0)