You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Mongoose根据关联ObjectId的游戏文档状态更新MongoDB赛事文档状态?

Alright, let's break this down step by step. When a game's status changes, we need to find all competitions linked to that game, evaluate the statuses of all their associated games, and update the competition's status following your defined rules. Here's how to implement this with Mongoose:


Step 1: Core Logic Implementation

First, we'll create a function that handles the full workflow: finding relevant competitions, fetching their linked game statuses, calculating the new competition status, and updating the database.

const mongoose = require('mongoose');
const Competition = require('./models/Competition'); // Update to your model path
const Game = require('./models/Game'); // Update to your model path

async function updateCompetitionStatusOnGameChange(gameId) {
  try {
    // Convert string ID to Mongoose ObjectId (if needed)
    const targetGameObjectId = mongoose.Types.ObjectId(gameId);

    // 1. Find all competitions that include the updated game
    const relatedCompetitions = await Competition.find({ games: targetGameObjectId });

    for (const competition of relatedCompetitions) {
      // 2. Fetch all game statuses linked to this competition
      const linkedGames = await Game.find(
        { _id: { $in: competition.games } },
        'gameStatus' // Only retrieve the status field for efficiency
      );
      const gameStatuses = linkedGames.map(game => game.gameStatus);

      // 3. Calculate new competition status based on rules
      let newCompetitionStatus;
      const hasPlaying = gameStatuses.includes('playing');
      const hasNotStarted = gameStatuses.includes('notStarted');
      const hasEnded = gameStatuses.includes('ended');

      if (gameStatuses.every(status => status === 'ended')) {
        newCompetitionStatus = 'ended';
      } else if (hasPlaying || (hasNotStarted && hasEnded)) {
        newCompetitionStatus = 'playing';
      } else {
        newCompetitionStatus = 'notStarted';
      }

      // 4. Update the competition's status
      await Competition.findByIdAndUpdate(
        competition._id,
        { competitionStatus: newCompetitionStatus },
        { new: true } // Optional: returns the updated document
      );

      console.log(`Updated competition ${competition.compeititionName} to status: ${newCompetitionStatus}`);
    }
  } catch (error) {
    console.error('Failed to update competition status:', error);
    throw error;
  }
}

// Call this function after updating a game's status, e.g.:
// updateCompetitionStatusOnGameChange('617...b18');

Step 2: Optimized Version with Aggregation

For better performance (especially with large datasets), use MongoDB's aggregation pipeline to fetch competitions and their linked game statuses in a single database call, reducing round trips:

async function updateCompetitionStatusOnGameChangeOptimized(gameId) {
  try {
    const targetGameObjectId = mongoose.Types.ObjectId(gameId);

    // Use aggregation to join competitions with their games and extract statuses
    const competitionsWithStatusData = await Competition.aggregate([
      { $match: { games: targetGameObjectId } },
      {
        $lookup: {
          from: 'games', // Use your actual games collection name (not model name)
          localField: 'games',
          foreignField: '_id',
          as: 'linkedGames'
        }
      },
      {
        $project: {
          compeititionName: 1,
          gameStatuses: { $map: { input: '$linkedGames', as: 'g', in: '$$g.gameStatus' } }
        }
      }
    ]);

    for (const comp of competitionsWithStatusData) {
      // Reuse the same status calculation logic as before
      let newCompetitionStatus;
      const hasPlaying = comp.gameStatuses.includes('playing');
      const hasNotStarted = comp.gameStatuses.includes('notStarted');
      const hasEnded = comp.gameStatuses.includes('ended');

      if (comp.gameStatuses.every(status => status === 'ended')) {
        newCompetitionStatus = 'ended';
      } else if (hasPlaying || (hasNotStarted && hasEnded)) {
        newCompetitionStatus = 'playing';
      } else {
        newCompetitionStatus = 'notStarted';
      }

      await Competition.findByIdAndUpdate(comp._id, { competitionStatus: newCompetitionStatus });
    }
  } catch (error) {
    console.error('Failed to update competition status:', error);
    throw error;
  }
}

Key Notes

  • Model Setup: Ensure your Competition model defines the games field as an array of ObjectId references:
    const competitionSchema = new mongoose.Schema({
      compeititionName: String,
      games: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Game' }],
      competitionStatus: String
    });
    
  • Error Handling: The examples include basic error handling, but you can extend this to fit your application's needs (e.g., logging to a service, alerting).
  • Performance: The aggregation version is preferred for large datasets since it minimizes database requests.

内容的提问来源于stack exchange,提问作者YulePale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 09:29:08