Skip to main content

Leaderboards API reference

Using the Momento Leaderboards

Momento Leaderboards is a first-class service with purpose-built APIs that supports leaderboards with tens of millions of items and rapid ingestion/querying/updates.

Leaderboard Client

To create and interact with leaderboards, you must first create a LeaderboardClient.

new PreviewLeaderboardClient({
configuration: LeaderboardConfigurations.Laptop.v1(),
credentialProvider: CredentialProvider.fromEnvironmentVariable({
environmentVariableName: 'MOMENTO_API_KEY',
}),
});

Then you can create a leaderboard by specifying a cache and leaderboard name.

// You can create multiple leaderboards using the same leaderboard client
// but with different cache and leaderboard names
leaderboardClient.leaderboard('test-cache', 'momento-leaderboard');
leaderboardClient.leaderboard('test-cache', 'acorns-leaderboard');

// Leaderboard and cache names must be non-empty strings
try {
leaderboardClient.leaderboard('test-cache', ' ');
} catch (error) {
console.log('Expected error creating a leaderboard with invalid leaderboard name:', error);
}

Leaderboard Methods

Upsert elements

Inserts elements if they do not already exist in the leaderboard. Updates elements if they do already exist in the leaderboard. There are no partial failures; an upsert call will either succeed or fail.

The ID can be a player identifier, session identifier, browser identifier or any other kind of identifier you want to use for this scoreboard. The full unsigned 64 bit range is allowed here, between 0 and 2^63-1 inclusive. An id can only appear in a leaderboard one time, meaning you can't have two scores for one player unless that player has two ids!

NameTypeDescription
elementsMap<number, number>A Map or Record of elements (id,score pairs) to upsert.
Method response object
  • Success
  • Error

See response objects for specific information.

// Upsert a set of elements as a Map
const elements1: Map<number, number> = new Map([
[123, 100.0],
[234, 200.0],
[345, 300.0],
[456, 400.0],
]);
const result1 = await leaderboard.upsert(elements1);
if (result1 instanceof LeaderboardUpsert.Success) {
console.log('Successfully upserted elements to leaderboard');
} else if (result1 instanceof LeaderboardUpsert.Error) {
console.log('Upsert error:', result1.message());
throw new Error(
`An error occurred while attempting to call upsert on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result1.errorCode()}: ${result1.message()}`
);
}

// Or upsert a set of elements as a Record
const elements2: Record<number, number> = {
567: 500,
678: 600,
789: 700,
890: 800,
};
const result2 = await leaderboard.upsert(elements2);
if (result2 instanceof LeaderboardUpsert.Success) {
console.log('Successfully upserted elements to leaderboard');
} else if (result2 instanceof LeaderboardUpsert.Error) {
console.log('Upsert error:', result2.message());
throw new Error(
`An error occurred while attempting to call upsert on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result2.errorCode()}: ${result2.message()}`
);
}

Upsert is implemented as a batched operation, so for large leaderboards, you can upsert in batches of up to 8192 elements.

// To upsert a large number of elements, you must upsert
// in batches of up to 8192 elements at a time.
const elements = [...Array(20000).keys()].map(i => {
return {id: i + 1, score: i * Math.random()};
});
for (let i = 0; i < 20000; i += 8192) {
// Create a Map containing 8192 elements at a time
const batch = new Map(elements.slice(i, i + 8192).map(obj => [obj['id'], obj['score']]));

// Then upsert one batch at a time until all elements have been ingested
const result = await leaderboard.upsert(batch);
if (result instanceof LeaderboardUpsert.Error) {
console.log(`Error upserting batch [${i}, ${i + 8192})`);
}
}

Fetch elements by score

Fetches elements that fall within the specified min and max scores.

Elements with the same score will be returned in alphanumerical order based on their ID (e.g. IDs of elements with the same score would be returned in the order [1, 10, 123, 2, 234, ...] rather than [1, 2, 10, 123, 234, ...]).

NameTypeDescription
minScoreOptional[number]Inclusive lower bound for the score range. Defaults to -inf.
maxScoreOptional[number]Exclusive upper bound for the score range. Defaults to +inf.
orderOptional[Ascending / Descending]The order to fetch the elements in. Defaults to ascending, meaning 0 is the lowest-scoring rank.
offsetOptional[number]The number of elements to skip before returning the first element. Defaults to 0. Note: this is not the score of the first element to return, but the number of elements of the result set to skip before returning the first element.
countOptional[number]The maximum number of elements to return. Defaults to 8192, which is the maximum that can be fetched per request.
Method response object
  • Success
    • values(): {id: number, score: number, rank: number}[]
  • Error

See response objects for specific information.

// By default, FetchByScore will fetch the elements from the entire score range
// with zero offset in ascending order. It can return 8192 elements at a time.
const result1 = await leaderboard.fetchByScore();
if (result1 instanceof LeaderboardFetch.Success) {
console.log('Successfully fetched elements using open score range:');
result1.values().forEach(element => {
console.log(`\tId: ${element.id} | Rank: ${element.rank} | Score: ${element.score}`);
});
} else if (result1 instanceof LeaderboardFetch.Error) {
throw new Error(
`An error occurred while attempting to call fetchByScore with no options on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result1.errorCode()}: ${result1.message()}`
);
}

// Example specifying all FetchByScore options. You can provide any subset of these options
// to modify your FetchByScore request.
const result2 = await leaderboard.fetchByScore({
minScore: 10,
maxScore: 600,
order: LeaderboardOrder.Descending,
offset: 2,
count: 10,
});
if (result2 instanceof LeaderboardFetch.Success) {
console.log('Successfully fetched elements by score using all options:');
result2.values().forEach(element => {
console.log(`\tId: ${element.id} | Rank: ${element.rank} | Score: ${element.score}`);
});
} else if (result2 instanceof LeaderboardFetch.Error) {
throw new Error(
`An error occurred while attempting to call fetchByScore with all options on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result2.errorCode()}: ${result2.message()}`
);
}

FetchByScore is implemented as a batch operation, so for large leaderboards, you can fetch in batches of up to 8192 elements. You can page through multiple elements that fall within the requested score range using the offset parameter until you receive an empty list, which indicates the end of the requested elements.

// Use the offset option to paginate through your results if your leaderboard
// has more than 8192 elements.
for (let offset = 0; offset < 20000; offset += 8192) {
const result = await leaderboard.fetchByScore({offset});
if (result instanceof LeaderboardFetch.Success) {
processBatch(result.values());
} else if (result instanceof LeaderboardFetch.Error) {
console.log(`Error fetching batch [${offset}, ${offset + 8192})`);
}
}

Fetch elements by rank

Fetches elements that fall within the specified min and max ranks.

NameTypeDescription
startRanknumberInclusive lower bound for the rank range. Defaults to 0.
endRanknumberExclusive upper bound for the rank range. Defaults to startRank + 8192.
orderOptional[Ascending / Descending]The order to fetch the elements in. Defaults to ascending, meaning 0 is the lowest-scoring rank.
Method response object
  • Success
    • values(): {id: number, score: number, rank: number}[]
  • Error

See response objects for specific information.

// By default, FetchByRank will fetch the elements in the range [startRank, endRank)
// in ascending order, meaning rank 0 is for the lowest score.
const result1 = await leaderboard.fetchByRank(0, 10);
if (result1 instanceof LeaderboardFetch.Success) {
console.log('Successfully fetched elements in rank range [0,10)');
result1.values().forEach(element => {
console.log(`\tId: ${element.id} | Rank: ${element.rank} | Score: ${element.score}`);
});
} else if (result1 instanceof LeaderboardFetch.Error) {
throw new Error(
`An error occurred while attempting to call fetchByRank with no options on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result1.errorCode()}: ${result1.message()}`
);
}

For large leaderboards, you will need to fetch in batches of up to 8192 elements.

// Use the startRank and endRank options to paginate through your leaderboard
// if your leaderboard has more than 8192 elements
for (let rank = 0; rank < 20000; rank += 8192) {
const result = await leaderboard.fetchByRank(rank, rank + 8192, {order: LeaderboardOrder.Descending});
if (result instanceof LeaderboardFetch.Success) {
processBatch(result.values());
} else if (result instanceof LeaderboardFetch.Error) {
console.log(`Error fetching batch [${rank}, ${rank + 8192})`);
}
}

Fetch elements by ID

Fetches elements given a list of element IDs.

NameTypeDescription
idsArray<number>The ids of the elements whose rank we are retrieving.
orderOptional[Ascending / Descending]The order to fetch the elements in. Defaults to ascending, meaning 0 is the lowest-scoring rank.
Method response object
  • Success
    • values(): {id: number, score: number, rank: number}[]
  • Error

See response objects for specific information.

// Provide a list of element IDs to get their ranks in ascending or descending order
const result = await leaderboard.getRank([123, 456, 789], {
order: LeaderboardOrder.Descending,
});
if (result instanceof LeaderboardFetch.Success) {
console.log('Successfully fetched the rank of 3 elements:');
result.values().forEach(element => {
console.log(`\tId: ${element.id} | Rank: ${element.rank} | Score: ${element.score}`);
});
} else if (result instanceof LeaderboardFetch.Error) {
throw new Error(
`An error occurred while attempting to call getRank on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result.errorCode()}: ${result.message()}`
);
}

Get leaderboard length

Gets the number of entries in the leaderboard. There are no parameters for this method; the leaderboard name is inferred from the Leaderboard object.

Method response object
  • Success
    • length(): number
  • Error

See response objects for specific information.

const result = await leaderboard.length();
if (result instanceof LeaderboardLength.Success) {
console.log('Successfully retrieved leaderboard length:', result.length());
} else if (result instanceof LeaderboardLength.Error) {
throw new Error(
`An error occurred while attempting to call length on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result.errorCode()}: ${result.message()}`
);
}

Remove elements

Removes elements with the specified IDs.

NameTypeDescription
idsArray<number>An Array of element IDs for the elements you want to remove.
Method response object
  • Success
  • Error

See response objects for specific information.

// Provide a list of element IDs to delete those elements
const result = await leaderboard.removeElements([123, 456, 789]);
if (result instanceof LeaderboardRemoveElements.Success) {
console.log('Successfully removed elements');
} else if (result instanceof LeaderboardRemoveElements.Error) {
throw new Error(
`An error occurred while attempting to call removeElements on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result.errorCode()}: ${result.message()}`
);
}

For large leaderboards, you will need to remove in batches of up to 8192 elements.

// You can remove batches of 8192 elements at a time
const ids = [...Array(20000).keys()];
for (let i = 0; i < 20000; i += 8192) {
const result = await leaderboard.removeElements(ids.slice(i, i + 8192));
if (result instanceof LeaderboardRemoveElements.Error) {
console.log(`Error removing batch [${i}, ${i + 8192})`);
}
}

Delete leaderboard

Deletes the leaderboard. There are no parameters for this method; the leaderboard name is inferred from the Leaderboard object.

Method response object
  • Success
  • Error

See response objects for specific information.

const result = await leaderboard.delete();
if (result instanceof LeaderboardDelete.Success) {
console.log('Successfully deleted the leaderboard');
} else if (result instanceof LeaderboardDelete.Error) {
throw new Error(
`An error occurred while attempting to call delete on leaderboard 'momento-leaderboard' in cache 'test-cache': ${result.errorCode()}: ${result.message()}`
);
}