Skip to content

Commit f852f52

Browse files
authored
feat(shell-api): add collection.getShardLocation helper method MONGOSH-1996 (#2467)
1 parent af7658f commit f852f52

File tree

5 files changed

+128
-1
lines changed

5 files changed

+128
-1
lines changed

.github/workflows/smoke-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
node: [20.x, 22.x, 23.x]
1818
fail-fast: false
1919
runs-on: ${{ matrix.runner }}-latest
20-
timeout-minutes: 15
20+
timeout-minutes: 20 # Installing dependencies on windows can take a while
2121
env:
2222
npm_config_loglevel: verbose
2323
npm_config_foreground_scripts: "true"

packages/autocomplete/src/index.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ describe('completer.completer', function () {
371371
'checkMetadataConsistency',
372372
'analyzeShardKey',
373373
'configureQueryAnalyzer',
374+
// 8.0+
375+
'getShardLocation',
374376
].includes(c)
375377
)
376378
.map((c) => `${i}${c}`);

packages/i18n/src/locales/en_US.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,12 @@ const translations: Catalog = {
873873
'Prints the data distribution statistics for a sharded collection.',
874874
example: 'db.coll.getShardDistribution()',
875875
},
876+
getShardLocation: {
877+
link: 'https://mongodb.com/docs/manual/reference/method/db.collection.getShardLocation',
878+
description:
879+
'Returns a document containing the shards where this collection is located as well as whether the collection itself is sharded.',
880+
example: 'db.coll.getShardLocation()',
881+
},
876882
analyzeShardKey: {
877883
link: 'https://mongodb.com/docs/manual/reference/method/db.collection.analyzeShardKey',
878884
description:

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,75 @@ describe('Collection', function () {
23632363
});
23642364
});
23652365

2366+
describe('getShardLocation', function () {
2367+
let collections: Document[];
2368+
let serviceProviderCursor: StubbedInstance<ServiceProviderAggregationCursor>;
2369+
2370+
beforeEach(function () {
2371+
collections = [];
2372+
serviceProviderCursor =
2373+
stubInterface<ServiceProviderAggregationCursor>();
2374+
serviceProvider.aggregateDb.returns(serviceProviderCursor);
2375+
2376+
serviceProviderCursor.toArray.resolves(collections);
2377+
});
2378+
2379+
it('calls $listClusterCatalog', async function () {
2380+
collections = [
2381+
{
2382+
ns: collection.getFullName(),
2383+
shards: ['foo', 'bar'],
2384+
sharded: true,
2385+
},
2386+
];
2387+
serviceProviderCursor.toArray.resolves(collections);
2388+
2389+
const shardLocation = await collection.getShardLocation();
2390+
expect(shardLocation).to.deep.equal({
2391+
shards: ['foo', 'bar'],
2392+
sharded: true,
2393+
});
2394+
2395+
expect(serviceProvider.aggregateDb).to.have.been.calledOnce;
2396+
const args = serviceProvider.aggregateDb.getCall(0).args;
2397+
expect(args[0]).to.equal(database.getName());
2398+
expect(args[1]).to.deep.equal([
2399+
{
2400+
$listClusterCatalog: {
2401+
shards: true,
2402+
},
2403+
},
2404+
{
2405+
$match: {
2406+
ns: collection.getFullName(),
2407+
},
2408+
},
2409+
{
2410+
$project: {
2411+
_id: 0,
2412+
shards: 1,
2413+
sharded: 1,
2414+
},
2415+
},
2416+
]);
2417+
});
2418+
2419+
it('throws for non-existent collection', async function () {
2420+
try {
2421+
await collection.getShardLocation();
2422+
expect.fail('Expected getShardLocation to throw');
2423+
} catch (err) {
2424+
if (err instanceof MongoshRuntimeError) {
2425+
expect(err.message).to.include(
2426+
`Error finding location information for ${collection.getFullName()}`
2427+
);
2428+
} else {
2429+
expect.fail('Expected error to be a MongoshRuntimeError');
2430+
}
2431+
}
2432+
});
2433+
});
2434+
23662435
describe('analyzeShardKey', function () {
23672436
it('calls serviceProvider.runCommand on the admin database', async function () {
23682437
await collection.analyzeShardKey({ myKey: 1 });
@@ -2999,6 +3068,11 @@ describe('Collection', function () {
29993068
watch: { i: 1 },
30003069
getSearchIndexes: { i: 3 },
30013070
checkMetadataConsistency: { m: 'runCursorCommand', i: 2 },
3071+
getShardLocation: {
3072+
i: 2,
3073+
m: 'aggregateDb',
3074+
e: true,
3075+
},
30023076
};
30033077
const ignore: (keyof (typeof Collection)['prototype'])[] = [
30043078
'getShardDistribution',

packages/shell-api/src/collection.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,51 @@ export class Collection<
22822282
);
22832283
}
22842284

2285+
@returnsPromise
2286+
@topologies([Topologies.Sharded])
2287+
@apiVersions([])
2288+
@serverVersions(['8.0.10', ServerVersions.latest])
2289+
async getShardLocation(): Promise<{
2290+
shards: string[];
2291+
sharded: boolean;
2292+
}> {
2293+
this._emitCollectionApiCall('getShardLocation', {});
2294+
2295+
const result = await (
2296+
await this._database.aggregate([
2297+
{
2298+
$listClusterCatalog: {
2299+
shards: true,
2300+
},
2301+
},
2302+
{
2303+
$match: {
2304+
ns: this.getFullName(),
2305+
},
2306+
},
2307+
{
2308+
$project: {
2309+
_id: 0,
2310+
shards: 1,
2311+
sharded: 1,
2312+
},
2313+
},
2314+
])
2315+
).toArray();
2316+
2317+
if (result.length > 0) {
2318+
return {
2319+
shards: result[0].shards,
2320+
sharded: result[0].sharded,
2321+
};
2322+
}
2323+
2324+
throw new MongoshRuntimeError(
2325+
`Error finding location information for ${this.getFullName()}`,
2326+
CommonErrors.CommandFailed
2327+
);
2328+
}
2329+
22852330
@serverVersions(['3.1.0', ServerVersions.latest])
22862331
@topologies([Topologies.ReplSet, Topologies.Sharded])
22872332
@apiVersions([1])

0 commit comments

Comments
 (0)