Reupdate the database will not roll back the previous database state

I've got this code for updating the match which will also update the other 3 models player team and tournament the code goes like this
const updateMatch = async (req, res) => {
try {
const { matchId, team1Players, team2Players } = req.body;
const match = await MatchModel.findById(matchId);
if (!match) {
return res.status(404).json({ message: 'Match not found' });
}
// Backup old values
const previousPlayerStats = {};
match.player_stats.forEach((stat) => {
previousPlayerStats[stat.player_id] = {
points: stat.points,
assists: stat.assists,
rebounds: stat.rebounds,
};
});
const previousTeam1Points = match.team_1_total_points || 0;
const previousTeam2Points = match.team_2_total_points || 0;
const previousWinner = match.winner;
// REVERSE old player stats
for (const stat of match.player_stats) {
const player = await PlayerModel.findById(stat.player_id);
if (player) {
player.total_points -= stat.points;
player.total_assists -= stat.assists;
player.total_rebounds -= stat.rebounds;
await player.save();
}
}
// APPLY new player stats
const applyNewStats = async (players) => {
for (const player of players) {
const playerDoc = await PlayerModel.findById(player.playerId);
if (playerDoc) {
playerDoc.total_points += player.points;
playerDoc.total_assists += player.assists;
playerDoc.total_rebounds += player.rebounds;
await playerDoc.save();
}
}
};
await applyNewStats(team1Players);
await applyNewStats(team2Players);
// Update match.player_stats
match.player_stats = [
...team1Players.map((p) => ({
player_id: p.playerId,
team_id: match.team_1,
points: p.points,
assists: p.assists,
rebounds: p.rebounds,
})),
...team2Players.map((p) => ({
player_id: p.playerId,
team_id: match.team_2,
points: p.points,
assists: p.assists,
rebounds: p.rebounds,
})),
];
// Calculate new totals
const team1TotalPoints = team1Players.reduce((sum, p) => sum + p.points, 0);
const team2TotalPoints = team2Players.reduce((sum, p) => sum + p.points, 0);
let newWinner = null;
if (team1TotalPoints > team2TotalPoints) newWinner = match.team_1;
else if (team2TotalPoints > team1TotalPoints) newWinner = match.team_2;
// Update teams
const updateTeam = async (teamId, isNewWinner, oldPoints, newPoints, wasPreviousWinner) => {
const team = await TeamModel.findById(teamId);
if (team) {
team.team_details.total_points_scored -= oldPoints;
team.team_details.total_points_scored += newPoints;
// Adjust win/loss if changed
if (wasPreviousWinner && !isNewWinner) {
team.team_details.matches_won -= 1;
team.team_details.matches_lost += 1;
} else if (!wasPreviousWinner && isNewWinner) {
team.team_details.matches_won += 1;
team.team_details.matches_lost -= 1;
}
await team.save();
}
};
await updateTeam(match.team_1, newWinner === match.team_1, previousTeam1Points, team1TotalPoints, previousWinner === match.team_1);
await updateTeam(match.team_2, newWinner === match.team_2, previousTeam2Points, team2TotalPoints, previousWinner === match.team_2);
match.team_1_total_points = team1TotalPoints;
match.team_2_total_points = team2TotalPoints;
match.winner = newWinner;
await match.save();
res.status(200).json({ message: 'Match updated successfully', match });
} catch (error) {
console.log(error);
res.status(500).json({ message: error.message });
}
};
the problem araises when I make a mistake in updating Suppose I put 19 instead of 10, which will increment 19 in all models and I again reupdate with correct value which is 10 which will again reincrement eventually making 29 instead of 10 So, I want to rollback the database to previous state and match is being rollback but not players, tournament and team Can you please suggest me a better approach or any update on the code. Feel free to ask for other code The frontend Code goes like this
import axios from 'axios';
const UpdateMatch = ({ match, onClose }) => {
const [updatedTeam1Players, setUpdatedTeam1Players] = useState([]);
const [updatedTeam2Players, setUpdatedTeam2Players] = useState([]);
useEffect(() => {
console.log('Received match details:', match);
// Initialize the updated state with the player's stats from playerStats
setUpdatedTeam1Players(
match.team1Players.map((player) => {
const playerStats = match.playerStats.find(
(stats) => stats.player_id === player._id && stats.team_id === match.team1Id
);
return {
playerId: player._id,
name: player.name,
points: playerStats ? playerStats.points : 0,
assists: playerStats ? playerStats.assists : 0,
rebounds: playerStats ? playerStats.rebounds : 0,
};
})
);
setUpdatedTeam2Players(
match.team2Players.map((player) => {
const playerStats = match.playerStats.find(
(stats) => stats.player_id === player._id && stats.team_id === match.team2Id
);
return {
playerId: player._id,
name: player.name,
points: playerStats ? playerStats.points : 0,
assists: playerStats ? playerStats.assists : 0,
rebounds: playerStats ? playerStats.rebounds : 0,
};
})
);
}, [match]);
const handleInputChange = (team, playerId, field, value) => {
const updatePlayer = (players) =>
players.map((player) =>
player.playerId === playerId ? { ...player, [field]: parseInt(value, 10) || 0 } : player
);
if (team === 'team1') {
setUpdatedTeam1Players(updatePlayer(updatedTeam1Players));
} else {
setUpdatedTeam2Players(updatePlayer(updatedTeam2Players));
}
};
const handleUpdateMatch = () => {
const updatedMatchDetails = {
matchId: match.matchId,
team1Players: updatedTeam1Players.map((player) => ({
playerId: player.playerId,
points: player.points,
assists: player.assists,
rebounds: player.rebounds,
})),
team2Players: updatedTeam2Players.map((player) => ({
playerId: player.playerId,
points: player.points,
assists: player.assists,
rebounds: player.rebounds,
})),
};
console.log('Updated Match Details:', updatedMatchDetails);
// Call API to update match details
axios
.post('http://localhost:8000/api/match/match/update', updatedMatchDetails)
.then((response) => {
console.log('Match updated successfully:', response.data);
if (response.status === 200) {
alert('Match updated successfully');
} else {
alert('Match not updated successfully');
}
})
.catch((error) => {
console.error('Error updating match:', error);
});
};
return (
<div className="p-4">
<h2 className="text-xl font-bold mb-4">Update Match</h2>
<div className="mb-4">
<h3 className="text-lg font-semibold">Tournament: {match.tournamentName}</h3>
</div>
<div className="flex justify-between mb-4">
<div>
<h4 className="text-md font-semibold">Team 1: {match.team1Name}</h4>
<table className="min-w-full bg-white border border-gray-300 mt-2">
<thead>
<tr className="bg-gray-100">
<th className="py-2 px-4 text-left border-b border-gray-300">Player's Name</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Points</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Assists</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Rebounds</th>
</tr>
</thead>
<tbody>
{updatedTeam1Players.map((player) => (
<tr key={player.playerId} className="hover:bg-gray-50">
<td className="border px-4 py-2 text-left">{player.name}</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.points}
onChange={(e) =>
handleInputChange('team1', player.playerId, 'points', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.assists}
onChange={(e) =>
handleInputChange('team1', player.playerId, 'assists', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.rebounds}
onChange={(e) =>
handleInputChange('team1', player.playerId, 'rebounds', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div>
<h4 className="text-md font-semibold">Team 2: {match.team2Name}</h4>
<table className="min-w-full bg-white border border-gray-300 mt-2">
<thead>
<tr className="bg-gray-100">
<th className="py-2 px-4 text-left border-b border-gray-300">Player's Name</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Points</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Assists</th>
<th className="py-2 px-4 text-left border-b border-gray-300">Rebounds</th>
</tr>
</thead>
<tbody>
{updatedTeam2Players.map((player) => (
<tr key={player.playerId} className="hover:bg-gray-50">
<td className="border px-4 py-2 text-left">{player.name}</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.points}
onChange={(e) =>
handleInputChange('team2', player.playerId, 'points', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.assists}
onChange={(e) =>
handleInputChange('team2', player.playerId, 'assists', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
<td className="border px-4 py-2 text-left">
<input
type="number"
value={player.rebounds}
onChange={(e) =>
handleInputChange('team2', player.playerId, 'rebounds', e.target.value)
}
className="w-full p-1 border border-gray-300 rounded"
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="flex justify-between mt-4">
<button
type="button"
onClick={onClose}
className="bg-red-500 text-white px-4 py-2 rounded"
>
Close
</button>
<button
type="button"
className="bg-blue-500 text-white px-4 py-2 rounded"
onClick={handleUpdateMatch}
>
Update Match
</button>
</div>
</div>
);
};
export default UpdateMatch;
Answer
Made simple adjustments that is the input can be negative value and user have to input the value accordingly increment or deceremnt Not the best and scaleabel approach but does the work Can you guyz please suggest me a better one please
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles