Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/compass-crud/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,6 @@ export type { DocumentListViewProps } from './components/document-list-view';
export { default as DocumentListView } from './components/document-list-view';
export type { DocumentJsonViewProps } from './components/document-json-view';
export { default as DocumentJsonView } from './components/document-json-view';

// Export utility functions for use by other packages
export { fetchShardingKeys } from './utils';
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,17 @@ type PropertyFieldProps = {
cardinality?: RegularIndex['cardinality'];
extra?: RegularIndex['extra'];
properties: RegularIndex['properties'];
isShardKeyIndex?: boolean;
};

const HIDDEN_INDEX_TEXT = 'HIDDEN';
const SHARD_KEY_INDEX_TEXT = 'SHARD KEY';

const PropertyField: React.FunctionComponent<PropertyFieldProps> = ({
extra,
properties,
cardinality,
isShardKeyIndex,
}) => {
return (
<div className={containerStyles}>
Expand All @@ -85,6 +88,12 @@ const PropertyField: React.FunctionComponent<PropertyFieldProps> = ({
/>
);
})}
{isShardKeyIndex && (
<PropertyBadgeWithTooltip
text={SHARD_KEY_INDEX_TEXT}
link={getIndexHelpLink('shard-key') ?? '#'}
/>
)}
{cardinality === 'compound' && (
<PropertyBadgeWithTooltip
text={cardinality}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ function getRegularIndexInfo(
cardinality={index.cardinality}
extra={index.extra}
properties={index.properties}
isShardKeyIndex={index.isShardKeyIndex}
/>
),
status: <StatusField status={status} />,
Expand Down
50 changes: 45 additions & 5 deletions packages/compass-indexes/src/modules/regular-indexes.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { isEqual, pick } from 'lodash';
import type { IndexDefinition } from 'mongodb-data-service';
import type { IndexDefinition, DataService } from 'mongodb-data-service';
import type { AnyAction } from 'redux';
import {
openToast,
showConfirmation as showConfirmationModal,
} from '@mongodb-js/compass-components';
import { fetchShardingKeys } from '@mongodb-js/compass-crud';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably move this to data service. We already aggregate indexes state from multiple sources, might as well add another one there instead of exposing this method from crud. Maybe we can have both: an explicit method to fetch shard keys, and also adding this logic to indexes method so that this info is available on the index


import { FetchStatuses, NOT_FETCHABLE_STATUSES } from '../utils/fetch-status';
import type { FetchStatus } from '../utils/fetch-status';
Expand Down Expand Up @@ -37,7 +38,9 @@ export type RegularIndex = Partial<IndexDefinition> &
| 'relativeSize'
| 'usageCount'
| 'buildProgress'
>;
> & {
isShardKeyIndex?: boolean;
};

export type InProgressIndex = Pick<IndexDefinition, 'name' | 'fields'> & {
id: string;
Expand Down Expand Up @@ -379,6 +382,28 @@ function pickCollectionStatFields(state: RootState) {
);
}

/**
* Determines if an index is built on shard key fields by comparing
* the index fields with the shard key fields.
*/
function isIndexOnShardKey(
indexFields: IndexDefinition['fields'],
shardKey: Record<string, unknown>
): boolean {
if (!shardKey || Object.keys(shardKey).length === 0) {
return false;
}

const shardKeyFields = Object.keys(shardKey);
const indexFieldNames = indexFields.map((field) => field.field);

// Check if index starts with shard key fields (prefix match)
// This covers both exact shard key indexes and compound indexes that include the shard key
return shardKeyFields.every(
(field, index) => indexFieldNames[index] === field
);
}

const fetchIndexes = (
reason: FetchReason
): IndexesThunkAction<Promise<void>, FetchIndexesActions> => {
Expand Down Expand Up @@ -426,10 +451,25 @@ const fetchIndexes = (
shouldFetchRollingIndexes
? rollingIndexesService.listRollingIndexes(namespace)
: undefined,
] as [Promise<IndexDefinition[]>, Promise<AtlasIndexStats[]> | undefined];
const [indexes, rollingIndexes] = await Promise.all(promises);
// Fetch shard key information to identify shard key indexes
fetchShardingKeys(dataService as DataService, namespace, {
signal: new AbortController().signal,
}).catch(() => ({})),
] as [
Promise<IndexDefinition[]>,
Promise<AtlasIndexStats[]> | undefined,
Promise<Record<string, unknown>>
];
const [indexes, rollingIndexes, shardKey] = await Promise.all(promises);

// Mark indexes that are built on shard key fields
const indexesWithShardKeyInfo = indexes.map((index) => ({
...index,
isShardKeyIndex: isIndexOnShardKey(index.fields, shardKey),
}));

const indexesBefore = pickCollectionStatFields(getState());
dispatch(fetchIndexesSucceeded(indexes, rollingIndexes));
dispatch(fetchIndexesSucceeded(indexesWithShardKeyInfo, rollingIndexes));
const indexesAfter = pickCollectionStatFields(getState());
if (
reason !== FetchReasons.INITIAL_FETCH &&
Expand Down
5 changes: 4 additions & 1 deletion packages/compass-indexes/src/stores/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ export type IndexesDataServiceProps =
| 'collectionStats'
| 'collectionInfo'
| 'listCollections'
| 'isListSearchIndexesSupported';
| 'isListSearchIndexesSupported'
// Required for shard key detection
| 'find'
| 'isCancelError';
export type IndexesDataService = Pick<DataService, IndexesDataServiceProps>;

export type IndexesPluginServices = {
Expand Down
1 change: 1 addition & 0 deletions packages/compass-indexes/src/utils/index-link-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const HELP_URLS = {
'https://docs.mongodb.com/master/reference/bson-type-comparison-order/#collation',
COLLATION_REF: 'https://docs.mongodb.com/master/reference/collation',
HIDDEN: 'https://www.mongodb.com/docs/manual/core/index-hidden/',
'SHARD-KEY': 'https://www.mongodb.com/docs/manual/core/sharding-shard-key/',
UNKNOWN: null,
};

Expand Down
9 changes: 9 additions & 0 deletions packages/compass-indexes/test/setup-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ const NOOP_DATA_PROVIDER: IndexesDataService = {
sample(namespace: string) {
return Promise.resolve([]);
},
// Required for shard key detection
// eslint-disable-next-line @typescript-eslint/no-unused-vars
find(ns: string, filter: unknown, options: unknown) {
return Promise.resolve([]);
},
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isCancelError(error: unknown) {
return false;
},
};

class FakeInstance extends EventEmitter {
Expand Down