Skip to content

questions.getRelated()

Retrieves questions that are algorithmically determined to be related to a specific question based on content similarity, tags, and other factors.

async getRelated(questionId: number, options?: GetLinkedQuestionsOptions): Promise<PaginatedLinkedOrRelatedQuestions>
ParameterTypeRequiredDescription
questionIdnumberYesThe unique identifier of the question to find related questions for
optionsGetLinkedQuestionsOptionsNoConfiguration options for pagination and sorting
PropertyTypeRequiredDefaultDescription
pagenumberNo1The page number to retrieve (1-based)
pageSize15 | 30 | 50 | 100No30Number of questions to return per page
sortLinkedOrRelatedQuestionsSortParameterNoSort by: "hot", "creation", "activity", or "score"
orderSortOrderNoSort order: "asc" (ascending) or "desc" (descending)

Returns a Promise<PaginatedLinkedOrRelatedQuestions> containing:

PropertyTypeDescription
totalCountnumberTotal number of related questions found
pageSizenumberNumber of items per page
pagenumberCurrent page number
totalPagesnumberTotal number of pages available
sortLinkedOrRelatedQuestionsSortParameterSort parameter used
orderSortOrderSort order used
itemsQuestionSummaryResponseModel[]Array of related question summaries
import { StackOverflowSDK } from 'so-teams-sdk';
const sdk = new StackOverflowSDK({
accessToken: 'your-access-token',
baseUrl: 'https://[your-site].stackenterprise.co/api/v3'
});
// Get related questions for a specific question
const relatedQuestions = await sdk.questions.getRelated(12345);
console.log(`Found ${relatedQuestions.totalCount} related questions`);
relatedQuestions.items.forEach(question => {
console.log(`- ${question.title}`);
console.log(` Score: ${question.score}, Answers: ${question.answerCount}`);
console.log(` Tags: ${question.tags?.map(t => t.name).join(', ')}`);
console.log(` Views: ${question.viewCount}`);
console.log('');
});
// Get hottest related questions (trending/active)
const hotRelatedQuestions = await sdk.questions.getRelated(12345, {
sort: 'hot',
order: 'desc',
pageSize: 20
});
console.log('Hottest related questions:');
hotRelatedQuestions.items.forEach((question, index) => {
console.log(`${index + 1}. ${question.title}`);
console.log(` Score: ${question.score}, Activity: ${question.lastActivityDate}`);
});
// Get highest scoring related questions
const topRelatedQuestions = await sdk.questions.getRelated(12345, {
sort: 'score',
order: 'desc',
pageSize: 15
});
console.log('\nTop scoring related questions:');
topRelatedQuestions.items.forEach((question, index) => {
console.log(`${index + 1}. ${question.title} (${question.score} points)`);
});
// Get newest related questions
const recentRelatedQuestions = await sdk.questions.getRelated(12345, {
sort: 'creation',
order: 'desc',
pageSize: 10
});
console.log('\nNewest related questions:');
recentRelatedQuestions.items.forEach(question => {
console.log(`- ${question.title}`);
console.log(` Created: ${question.creationDate}`);
});
Section titled “Related Questions Analysis and Recommendations”
async function analyzeRelatedQuestions(questionId: number) {
try {
// Get the original question and related questions
const [originalQuestion, relatedQuestions] = await Promise.all([
sdk.questions.get(questionId),
sdk.questions.getRelated(questionId, {
pageSize: 100,
sort: 'hot',
order: 'desc'
})
]);
console.log(`Analyzing related questions for: ${originalQuestion.title}`);
console.log(`Found ${relatedQuestions.totalCount} algorithmically related questions`);
if (relatedQuestions.totalCount === 0) {
console.log('No related questions found');
return { originalQuestion, relatedQuestions: [], analysis: null };
}
const analysis = {
totalRelated: relatedQuestions.totalCount,
similarity: {
tagOverlap: calculateTagOverlap(originalQuestion, relatedQuestions.items),
topicClusters: identifyTopicClusters(relatedQuestions.items),
difficultySpread: analyzeDifficultySpread(relatedQuestions.items)
},
engagement: {
averageScore: relatedQuestions.items.reduce((sum, q) => sum + (q.score || 0), 0) / relatedQuestions.items.length,
averageViews: relatedQuestions.items.reduce((sum, q) => sum + (q.viewCount || 0), 0) / relatedQuestions.items.length,
answeredRate: relatedQuestions.items.filter(q => q.isAnswered).length / relatedQuestions.items.length * 100,
totalAnswers: relatedQuestions.items.reduce((sum, q) => sum + (q.answerCount || 0), 0)
},
quality: {
highQuality: relatedQuestions.items.filter(q => (q.score || 0) >= 5).length,
mediumQuality: relatedQuestions.items.filter(q => (q.score || 0) >= 1 && (q.score || 0) < 5).length,
lowQuality: relatedQuestions.items.filter(q => (q.score || 0) < 1).length
},
recommendations: generateRelatedQuestionsRecommendations(originalQuestion, relatedQuestions.items),
topRecommendations: relatedQuestions.items
.sort((a, b) => calculateRelevanceScore(originalQuestion, b) - calculateRelevanceScore(originalQuestion, a))
.slice(0, 5)
};
console.log('\nRelated Questions Analysis:');
console.log(`- Average score: ${analysis.engagement.averageScore.toFixed(1)}`);
console.log(`- Average views: ${Math.round(analysis.engagement.averageViews)}`);
console.log(`- Answer rate: ${analysis.engagement.answeredRate.toFixed(1)}%`);
console.log(`- Quality distribution: High(${analysis.quality.highQuality}), Medium(${analysis.quality.mediumQuality}), Low(${analysis.quality.lowQuality})`);
console.log('\nTag Overlap Analysis:');
analysis.similarity.tagOverlap.forEach(([tag, count, percentage]) => {
console.log(`- ${tag}: ${count} questions (${percentage.toFixed(1)}%)`);
});
console.log('\nTop Recommended Related Questions:');
analysis.topRecommendations.forEach((q, index) => {
const relevanceScore = calculateRelevanceScore(originalQuestion, q);
console.log(`${index + 1}. ${q.title}`);
console.log(` Relevance: ${relevanceScore.toFixed(1)}, Score: ${q.score}, Answers: ${q.answerCount}`);
});
console.log('\nRecommendations:');
analysis.recommendations.forEach(rec => console.log(`- ${rec}`));
return { originalQuestion, relatedQuestions: relatedQuestions.items, analysis };
} catch (error) {
console.error('Related questions analysis failed:', error.message);
throw error;
}
}
function calculateTagOverlap(original: any, related: any[]): [string, number, number][] {
const originalTags = original.tags?.map(t => t.name) || [];
const tagOverlap = new Map<string, number>();
originalTags.forEach(tag => {
const count = related.filter(q =>
q.tags?.some(t => t.name === tag)
).length;
if (count > 0) {
tagOverlap.set(tag, count);
}
});
return Array.from(tagOverlap.entries())
.map(([tag, count]) => [tag, count, (count / related.length) * 100])
.sort(([,a], [,b]) => b - a);
}
function identifyTopicClusters(questions: any[]): Record<string, any[]> {
const clusters: Record<string, any[]> = {};
// Group by primary tag combinations
questions.forEach(question => {
const tags = question.tags?.map(t => t.name) || [];
const primaryTags = tags.slice(0, 2).sort();
const clusterKey = primaryTags.join('-') || 'untagged';
if (!clusters[clusterKey]) {
clusters[clusterKey] = [];
}
clusters[clusterKey].push(question);
});
// Filter clusters with meaningful size
Object.keys(clusters).forEach(key => {
if (clusters[key].length < 2) {
delete clusters[key];
}
});
return clusters;
}
function analyzeDifficultySpread(questions: any[]): { beginner: number, intermediate: number, advanced: number } {
return questions.reduce((spread, question) => {
const difficulty = assessQuestionDifficulty(question);
spread[difficulty]++;
return spread;
}, { beginner: 0, intermediate: 0, advanced: 0 });
}
function assessQuestionDifficulty(question: any): 'beginner' | 'intermediate' | 'advanced' {
const tags = question.tags?.map(t => t.name.toLowerCase()) || [];
const advancedKeywords = ['advanced', 'performance', 'architecture', 'optimization', 'design-patterns'];
const intermediateKeywords = ['async', 'promises', 'generics', 'middleware', 'patterns'];
if (tags.some(tag => advancedKeywords.some(keyword => tag.includes(keyword)))) {
return 'advanced';
}
if (tags.some(tag => intermediateKeywords.some(keyword => tag.includes(keyword))) || (question.score || 0) > 5) {
return 'intermediate';
}
return 'beginner';
}
function calculateRelevanceScore(original: any, related: any): number {
let score = 0;
// Tag similarity (40% weight)
const originalTags = new Set(original.tags?.map(t => t.name) || []);
const relatedTags = new Set(related.tags?.map(t => t.name) || []);
const commonTags = new Set([...originalTags].filter(x => relatedTags.has(x)));
const tagSimilarity = commonTags.size / Math.max(originalTags.size, relatedTags.size, 1);
score += tagSimilarity * 40;
// Quality score (30% weight)
const qualityScore = Math.min((related.score || 0) / 10, 1);
score += qualityScore * 30;
// Answer availability (20% weight)
const answerScore = related.isAnswered ? 1 : 0.5;
score += answerScore * 20;
// Activity recency (10% weight)
const daysSinceActivity = (Date.now() - new Date(related.lastActivityDate).getTime()) / (1000 * 60 * 60 * 24);
const recencyScore = Math.max(0, 1 - (daysSinceActivity / 365));
score += recencyScore * 10;
return score;
}
function generateRelatedQuestionsRecommendations(original: any, related: any[]): string[] {
const recommendations = [];
const highQualityRelated = related.filter(q => (q.score || 0) >= 5);
if (highQualityRelated.length > 0) {
recommendations.push(`${highQualityRelated.length} high-quality related questions available for deeper learning`);
}
const unansweredRelated = related.filter(q => !q.isAnswered);
if (unansweredRelated.length > 0) {
recommendations.push(`${unansweredRelated.length} unanswered related questions - opportunity to contribute`);
}
const recentRelated = related.filter(q => {
const daysSince = (Date.now() - new Date(q.creationDate).getTime()) / (1000 * 60 * 60 * 24);
return daysSince <= 30;
});
if (recentRelated.length > related.length * 0.2) {
recommendations.push('Topic has recent activity - consider following for updates');
}
const strongTagOverlap = related.filter(q => {
const originalTags = new Set(original.tags?.map(t => t.name) || []);
const questionTags = new Set(q.tags?.map(t => t.name) || []);
const overlap = new Set([...originalTags].filter(x => questionTags.has(x)));
return overlap.size >= 2;
});
if (strongTagOverlap.length > 0) {
recommendations.push(`${strongTagOverlap.length} questions with strong topical overlap for comprehensive understanding`);
}
return recommendations;
}
const relatedAnalysis = await analyzeRelatedQuestions(12345);
Section titled “Learning Path Generation from Related Questions”
async function createLearningPathFromRelated(questionId: number) {
console.log(`Creating learning path from related questions for question ${questionId}...`);
try {
const [originalQuestion, relatedQuestions] = await Promise.all([
sdk.questions.get(questionId),
sdk.questions.getRelated(questionId, { pageSize: 100 })
]);
console.log(`Building learning path for: ${originalQuestion.title}`);
if (relatedQuestions.totalCount === 0) {
console.log('No related questions found for learning path generation');
return null;
}
// Categorize questions by difficulty and topic
const categorizedQuestions = {
prerequisites: [],
core: [],
advanced: [],
supplementary: []
};
relatedQuestions.items.forEach(question => {
const difficulty = assessQuestionDifficulty(question);
const relevance = calculateRelevanceScore(originalQuestion, question);
if (relevance > 70 && difficulty === 'beginner') {
categorizedQuestions.prerequisites.push({ question, relevance, difficulty });
} else if (relevance > 60 && difficulty === 'intermediate') {
categorizedQuestions.core.push({ question, relevance, difficulty });
} else if (relevance > 50 && difficulty === 'advanced') {
categorizedQuestions.advanced.push({ question, relevance, difficulty });
} else if (relevance > 30) {
categorizedQuestions.supplementary.push({ question, relevance, difficulty });
}
});
// Sort by relevance within each category
Object.keys(categorizedQuestions).forEach(category => {
categorizedQuestions[category].sort((a, b) => b.relevance - a.relevance);
});
const learningPath = {
topic: extractMainTopic(originalQuestion),
originalQuestion: {
id: originalQuestion.id,
title: originalQuestion.title,
difficulty: assessQuestionDifficulty(originalQuestion)
},
path: {
prerequisites: categorizedQuestions.prerequisites.slice(0, 5),
core: categorizedQuestions.core.slice(0, 8),
advanced: categorizedQuestions.advanced.slice(0, 5),
supplementary: categorizedQuestions.supplementary.slice(0, 10)
},
estimatedStudyTime: calculateEstimatedStudyTime(categorizedQuestions),
progressTracking: {
completed: 0,
total: Object.values(categorizedQuestions).reduce((sum, cat) => sum + Math.min(cat.length, cat === categorizedQuestions.supplementary ? 10 : cat === categorizedQuestions.core ? 8 : 5), 0)
}
};
console.log(`\nLearning Path: ${learningPath.topic}`);
console.log(`Total questions in path: ${learningPath.progressTracking.total}`);
console.log(`Estimated study time: ${learningPath.estimatedStudyTime} hours`);
console.log('\nLearning Path Structure:');
if (learningPath.path.prerequisites.length > 0) {
console.log(`\n📚 Prerequisites (${learningPath.path.prerequisites.length}):`);
learningPath.path.prerequisites.forEach((item, index) => {
console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`);
});
}
if (learningPath.path.core.length > 0) {
console.log(`\n🎯 Core Topics (${learningPath.path.core.length}):`);
learningPath.path.core.forEach((item, index) => {
console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`);
});
}
if (learningPath.path.advanced.length > 0) {
console.log(`\n🚀 Advanced Topics (${learningPath.path.advanced.length}):`);
learningPath.path.advanced.forEach((item, index) => {
console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`);
});
}
if (learningPath.path.supplementary.length > 0) {
console.log(`\n📖 Supplementary Reading (${learningPath.path.supplementary.length}):`);
learningPath.path.supplementary.slice(0, 5).forEach((item, index) => {
console.log(`${index + 1}. ${item.question.title} (Relevance: ${item.relevance.toFixed(1)}%)`);
});
}
return learningPath;
} catch (error) {
console.error('Learning path generation failed:', error.message);
throw error;
}
}
function extractMainTopic(question: any): string {
const tags = question.tags?.map(t => t.name) || [];
// Priority topics
const priorityTopics = ['typescript', 'react', 'nodejs', 'python', 'javascript', 'java'];
const primaryTopic = tags.find(tag => priorityTopics.includes(tag.toLowerCase()));
if (primaryTopic) {
return primaryTopic.charAt(0).toUpperCase() + primaryTopic.slice(1);
}
// Use first tag or extract from title
if (tags.length > 0) {
return tags[0].charAt(0).toUpperCase() + tags[0].slice(1);
}
// Extract from title
const title = question.title.toLowerCase();
for (const topic of priorityTopics) {
if (title.includes(topic)) {
return topic.charAt(0).toUpperCase() + topic.slice(1);
}
}
return 'Programming';
}
function calculateEstimatedStudyTime(categorizedQuestions: any): number {
// Rough estimates: Prerequisites (15 min), Core (30 min), Advanced (45 min), Supplementary (10 min)
const timeEstimates = {
prerequisites: 0.25, // 15 minutes
core: 0.5, // 30 minutes
advanced: 0.75, // 45 minutes
supplementary: 0.17 // 10 minutes
};
let totalHours = 0;
Object.entries(categorizedQuestions).forEach(([category, questions]) => {
const maxQuestions = category === 'supplementary' ? 10 : category === 'core' ? 8 : 5;
const questionCount = Math.min(questions.length, maxQuestions);
totalHours += questionCount * timeEstimates[category];
});
return Math.round(totalHours * 10) / 10; // Round to 1 decimal place
}
const learningPath = await createLearningPathFromRelated(12345);
async function createRelatedQuestionsEngine() {
console.log('Creating related questions discovery engine...');
const discoveryCache = new Map<number, any>();
async function discoverRelatedQuestionsTree(rootQuestionId: number, depth: number = 2): Promise<any> {
if (discoveryCache.has(rootQuestionId)) {
return discoveryCache.get(rootQuestionId);
}
try {
const [rootQuestion, relatedQuestions] = await Promise.all([
sdk.questions.get(rootQuestionId),
sdk.questions.getRelated(rootQuestionId, { pageSize: 50, sort: 'hot' })
]);
const discoveryNode = {
id: rootQuestion.id,
title: rootQuestion.title,
tags: rootQuestion.tags?.map(t => t.name) || [],
score: rootQuestion.score,
depth: 0,
relatedQuestions: relatedQuestions.items.map(q => ({
id: q.id,
title: q.title,
score: q.score,
relevance: calculateRelevanceScore(rootQuestion, q),
tags: q.tags?.map(t => t.name) || []
})).sort((a, b) => b.relevance - a.relevance),
branches: []
};
discoveryCache.set(rootQuestionId, discoveryNode);
// Explore branches if depth allows
if (depth > 1) {
const topRelated = relatedQuestions.items.slice(0, 3); // Limit to prevent explosion
for (const related of topRelated) {
try {
const branch = await discoverRelatedQuestionsTree(related.id, depth - 1);
if (branch) {
branch.depth = 1;
discoveryNode.branches.push(branch);
}
} catch (error) {
console.error(`Failed to explore branch ${related.id}:`, error.message);
}
}
}
return discoveryNode;
} catch (error) {
console.error(`Discovery failed for question ${rootQuestionId}:`, error.message);
return null;
}
}
async function findTopicClusters(questionIds: number[]): Promise<Record<string, any[]>> {
const clusters: Record<string, any[]> = {};
for (const questionId of questionIds) {
try {
const relatedQuestions = await sdk.questions.getRelated(questionId, { pageSize: 30 });
relatedQuestions.items.forEach(question => {
const tags = question.tags?.map(t => t.name) || [];
// Create cluster keys from tag combinations
tags.slice(0, 2).forEach(tag => {
if (!clusters[tag]) {
clusters[tag] = [];
}
if (!clusters[tag].find(q => q.id === question.id)) {
clusters[tag].push({
id: question.id,
title: question.title,
score: question.score,
tags: tags
});
}
});
});
} catch (error) {
console.error(`Failed to cluster question ${questionId}:`, error.message);
}
}
// Filter clusters with meaningful size
Object.keys(clusters).forEach(key => {
if (clusters[key].length < 3) {
delete clusters[key];
} else {
// Sort by score within cluster
clusters[key].sort((a, b) => b.score - a.score);
}
});
return clusters;
}
async function generateDiscoveryReport(rootQuestionId: number): Promise<any> {
console.log(`Generating discovery report for question ${rootQuestionId}...`);
const discoveryTree = await discoverRelatedQuestionsTree(rootQuestionId, 2);
if (!discoveryTree) {
return null;
}
const allDiscoveredQuestions = [
...discoveryTree.relatedQuestions,
...discoveryTree.branches.flatMap(branch => branch.relatedQuestions || [])
];
// Remove duplicates
const uniqueQuestions = allDiscoveredQuestions.filter((question, index, array) =>
array.findIndex(q => q.id === question.id) === index
);
const report = {
rootQuestion: {
id: discoveryTree.id,
title: discoveryTree.title,
tags: discoveryTree.tags
},
discovery: {
totalDiscovered: uniqueQuestions.length,
directRelated: discoveryTree.relatedQuestions.length,
indirectRelated: uniqueQuestions.length - discoveryTree.relatedQuestions.length,
branches: discoveryTree.branches.length
},
quality: {
highQuality: uniqueQuestions.filter(q => q.score >= 5).length,
mediumQuality: uniqueQuestions.filter(q => q.score >= 1 && q.score < 5).length,
lowQuality: uniqueQuestions.filter(q => q.score < 1).length
},
topDiscoveries: uniqueQuestions
.sort((a, b) => b.relevance - a.relevance)
.slice(0, 10),
topicDistribution: analyzeTopicDistribution(uniqueQuestions)
};
console.log('\nDiscovery Report:');
console.log(`- Total questions discovered: ${report.discovery.totalDiscovered}`);
console.log(`- Direct relationships: ${report.discovery.directRelated}`);
console.log(`- Indirect relationships: ${report.discovery.indirectRelated}`);
console.log(`- Exploration branches: ${report.discovery.branches}`);
console.log('\nTop Discoveries:');
report.topDiscoveries.forEach((q, index) => {
console.log(`${index + 1}. ${q.title} (Relevance: ${q.relevance.toFixed(1)}, Score: ${q.score})`);
});
return report;
}
function analyzeTopicDistribution(questions: any[]): Record<string, number> {
const topicCounts: Record<string, number> = {};
questions.forEach(question => {
question.tags.forEach(tag => {
topicCounts[tag] = (topicCounts[tag] || 0) + 1;
});
});
return Object.fromEntries(
Object.entries(topicCounts)
.sort(([,a], [,b]) => b - a)
.slice(0, 10)
);
}
return {
discoverRelatedQuestionsTree,
findTopicClusters,
generateDiscoveryReport
};
}
const discoveryEngine = await createRelatedQuestionsEngine();
// Generate comprehensive discovery report
const discoveryReport = await discoveryEngine.generateDiscoveryReport(12345);
// Find topic clusters across multiple questions
const topicClusters = await discoveryEngine.findTopicClusters([12345, 12346, 12347]);
console.log('\nTopic Clusters:');
Object.entries(topicClusters).forEach(([topic, questions]) => {
console.log(`${topic}: ${questions.length} questions`);
});
// Team context related questions
const teamSDK = sdk.forTeam('team-123');
async function exploreTeamRelatedQuestions(questionId: number) {
try {
console.log(`Exploring team-related questions for question ${questionId}...`);
const [teamQuestion, teamRelatedQuestions] = await Promise.all([
teamSDK.questions.get(questionId),
teamSDK.questions.getRelated(questionId, {
pageSize: 50,
sort: 'hot'
})
]);
console.log(`Team Question: ${teamQuestion.title}`);
console.log(`Team-related questions found: ${teamRelatedQuestions.totalCount}`);
if (teamRelatedQuestions.totalCount === 0) {
console.log('No team-related questions found');
return null;
}
// Analyze team-specific relationship patterns
const teamAnalysis = {
internalQuestions: teamRelatedQuestions.items.filter(q =>
q.tags?.some(tag => ['internal', 'team', 'company'].includes(tag.name.toLowerCase()))
),
workflowRelated: teamRelatedQuestions.items.filter(q =>
q.tags?.some(tag => ['workflow', 'process', 'deployment', 'ci-cd'].includes(tag.name.toLowerCase()))
),
toolsAndInfrastructure: teamRelatedQuestions.items.filter(q =>
q.tags?.some(tag => ['tools', 'infrastructure', 'devops', 'monitoring'].includes(tag.name.toLowerCase()))
),
knowledgeSharing: teamRelatedQuestions.items.filter(q =>
q.tags?.some(tag => ['documentation', 'guide', 'best-practices', 'standards'].includes(tag.name.toLowerCase()))
),
crossTeamInteractions: teamRelatedQuestions.items.filter(q => {
// Questions that might involve multiple teams or external dependencies
return q.tags?.some(tag => ['api', 'integration', 'external', 'collaboration'].includes(tag.name.toLowerCase()));
})
};
console.log('\nTeam Related Questions Analysis:');
console.log(`- Internal questions: ${teamAnalysis.internalQuestions.length}`);
console.log(`- Workflow related: ${teamAnalysis.workflowRelated.length}`);
console.log(`- Tools & Infrastructure: ${teamAnalysis.toolsAndInfrastructure.length}`);
console.log(`- Knowledge sharing: ${teamAnalysis.knowledgeSharing.length}`);
console.log(`- Cross-team interactions: ${teamAnalysis.crossTeamInteractions.length}`);
// Show most relevant categories
if (teamAnalysis.knowledgeSharing.length > 0) {
console.log('\nKnowledge Sharing Opportunities:');
teamAnalysis.knowledgeSharing.slice(0, 3).forEach(q => {
console.log(`- ${q.title} (Score: ${q.score})`);
});
}
if (teamAnalysis.workflowRelated.length > 0) {
console.log('\nWorkflow Related Questions:');
teamAnalysis.workflowRelated.slice(0, 3).forEach(q => {
console.log(`- ${q.title} (Answers: ${q.answerCount})`);
});
}
// Generate team-specific recommendations
const teamRecommendations = [];
if (teamAnalysis.knowledgeSharing.length > 2) {
teamRecommendations.push('Consider creating a knowledge base from these related questions');
}
if (teamAnalysis.workflowRelated.length > 3) {
teamRecommendations.push('Multiple workflow questions suggest process documentation opportunities');
}
if (teamAnalysis.toolsAndInfrastructure.length > 0) {
teamRecommendations.push('Infrastructure questions could benefit from standardized solutions');
}
console.log('\nTeam Recommendations:');
teamRecommendations.forEach(rec => console.log(`- ${rec}`));
return {
teamQuestion,
relatedQuestions: teamRelatedQuestions.items,
analysis: teamAnalysis,
recommendations: teamRecommendations
};
} catch (error) {
console.error('Team related questions exploration failed:', error.message);
throw error;
}
}
const teamRelatedAnalysis = await exploreTeamRelatedQuestions(12345);
async function createRelatedQuestionsMonitor(questionId: number, checkInterval: number = 300000) {
console.log(`Starting related questions monitor for question ${questionId}`);
console.log(`Check interval: ${checkInterval / 1000} seconds`);
let previousRelatedCount = 0;
let previousTopRelated = [];
// Initial baseline
try {
const initialRelated = await sdk.questions.getRelated(questionId, { pageSize: 20 });
previousRelatedCount = initialRelated.totalCount;
previousTopRelated = initialRelated.items.slice(0, 5);
console.log(`Initial baseline: ${previousRelatedCount} related questions`);
} catch (error) {
console.error('Failed to establish baseline:', error.message);
return null;
}
const monitor = setInterval(async () => {
try {
const currentRelated = await sdk.questions.getRelated(questionId, {
pageSize: 20,
sort: 'hot'
});
const changes = [];
// Check for count changes
if (currentRelated.totalCount !== previousRelatedCount) {
const countChange = currentRelated.totalCount - previousRelatedCount;
changes.push({
type: 'count_change',
change: countChange,
newTotal: currentRelated.totalCount,
previousTotal: previousRelatedCount
});
}
// Check for new top related questions
const currentTopRelated = currentRelated.items.slice(0, 5);
const newQuestions = currentTopRelated.filter(current =>
!previousTopRelated.some(prev => prev.id === current.id)
);
if (newQuestions.length > 0) {
changes.push({
type: 'new_top_related',
newQuestions: newQuestions.map(q => ({
id: q.id,
title: q.title,
score: q.score
}))
});
}
// Check for score changes in existing top questions
const scoreChanges = currentTopRelated
.map(current => {
const previous = previousTopRelated.find(prev => prev.id === current.id);
if (previous && current.score !== previous.score) {
return {
id: current.id,
title: current.title,
previousScore: previous.score,
currentScore: current.score,
change: current.score - previous.score
};
}
return null;
})
.filter(Boolean);
if (scoreChanges.length > 0) {
changes.push({
type: 'score_changes',
changes: scoreChanges
});
}
if (changes.length > 0) {
console.log(`\n[${new Date().toLocaleTimeString()}] Related questions changes detected:`);
changes.forEach(change => {
switch (change.type) {
case 'count_change':
console.log(`- Total related questions: ${change.previousTotal}${change.newTotal} (${change.change > 0 ? '+' : ''}${change.change})`);
break;
case 'new_top_related':
console.log(`- New top related questions:`);
change.newQuestions.forEach(q => {
console.log(`${q.title} (Score: ${q.score})`);
});
break;
case 'score_changes':
console.log(`- Score changes in top related:`);
change.changes.forEach(sc => {
console.log(`${sc.title}: ${sc.previousScore}${sc.currentScore} (${sc.change > 0 ? '+' : ''}${sc.change})`);
});
break;
}
});
}
// Update baseline
previousRelatedCount = currentRelated.totalCount;
previousTopRelated = currentTopRelated;
} catch (error) {
console.error('Monitoring error:', error.message);
}
}, checkInterval);
// Return function to stop monitoring
return () => {
clearInterval(monitor);
console.log(`Stopped monitoring related questions for question ${questionId}`);
};
}
// Start monitoring (checks every 5 minutes)
const stopMonitoring = await createRelatedQuestionsMonitor(12345, 300000);
// Stop after 1 hour
setTimeout(() => {
if (stopMonitoring) stopMonitoring();
}, 3600000);

This method can throw the following errors:

Error TypeStatus CodeDescription
AuthenticationError401Invalid or missing authentication token
TokenExpiredError401Authentication token has expired
ForbiddenError403Insufficient permissions to access related questions
NotFoundError404Question with the specified ID does not exist
SDKErrorVariousOther API or network errors
import StackOverflowSDK, { NotFoundError, ForbiddenError, AuthenticationError } from 'so-teams-sdk';
const sdk = new StackOverflowSDK({
accessToken: 'your-access-token',
baseUrl: 'https://[your-site].stackenterprise.co/api/v3'
});
try {
const relatedQuestions = await sdk.questions.getRelated(12345, {
sort: 'hot',
order: 'desc',
pageSize: 25
});
console.log(`Found ${relatedQuestions.totalCount} related questions`);
} catch (error) {
if (error instanceof NotFoundError) {
console.error('Question not found');
} else if (error instanceof ForbiddenError) {
console.error('Access denied to related questions');
} else if (error instanceof AuthenticationError) {
console.error('Authentication required');
} else {
console.error('Failed to retrieve related questions:', error.message);
}
}
  • Algorithmic Relationships: Related questions are determined by content analysis, not explicit links
  • Dynamic Results: Related questions may change as the algorithm learns and content evolves
  • Similarity Factors: Typically based on tags, content similarity, user behavior, and other signals
  • Sort Options: "hot" combines recent activity with relevance; other options prioritize different factors
  • Content Discovery: Primary tool for discovering topically similar questions
  • Learning Aid: Useful for understanding topic breadth and finding comprehensive coverage
  • Quality Varies: Algorithmic relationships may include varying quality levels
  • Complementary Tool: Works best alongside linked questions and search for complete discovery
  • Performance Dependent: Results quality depends on platform’s recommendation algorithm sophistication