正在跳过多个findOneAndUpdate操作
我有一个forEach
循环,在其中查询文档,进行一些简单的数学计算,然后在集合中将updating
一个文档进行下一步。
问题是,很多时候UPDATE
操作中的一些随机操作不会更新文档。我不知道为什么会这样。是因为lock
吗?
我已经尝试在update
操作之前记录日志。数据都是正确的,但是当涉及到update
时,它将完全不会随机更新。在10次迭代中,可以说8次可以正常工作
const name = "foo_game";
players.forEach(({ id, team, username }) => {
let updatedStats = {};
Users.findOne({ id }).then(existingPlayer => {
if (!existingPlayer) return;
const { stats } = existingPlayer;
const existingStats = stats[pug.name];
if (!existingStats) return;
const presentWins = existingStats.won || 0;
const presentLosses = existingStats.lost || 0;
updatedStats = {
...existingStats,
won:
team === winningTeam
? presentWins + 1
: changeWinner
? presentWins - 1
: presentWins,
lost:
team !== winningTeam
? presentLosses + 1
: changeWinner
? presentLosses - 1
: presentLosses,
};
// THE CALCULATIONS ARE ALL CORRECT TILL THIS POINT
// THE UPDATE WIILL RANDOMLY NOT WORK
Users.findOneAndUpdate(
{ id, server_id: serverId },
{
$set: {
username,
stats: { ...stats, [name]: updatedStats },
},
},
{
upsert: true,
}
).exec();
});
});
回答如下:基本上,这里缺少的是findOne()
和findOneAndUpdate()
的异步操作不能保证在foreach()
完成之前完成。对于在其中具有异步操作的循环,使用forEach()
并不是一个不错的选择,但是这里的另一个要点是,由于MongoDB有更好的方法以及在向服务器发送[[one请求中,这是完全不必要的。
bulkWrite()
提供指令数组,而不是“循环”:
bulkWrite()
因此而不是循环,该或decrease当前值。请注意,如果当前在指定路径上未记录任何内容,那么它将创建具有逻辑确定的let server_id = serverId; // Alias one of your variables or just change it's name Users.bulkWrite( players.map(({ id, team, username }) => ({ "updateOne": { "filter": { _id, server_id }, "update": { "$set": { username }, "$inc": { [`stats.${name}.won`]: team === winningTeam ? 1 : changeWinner ? - 1 : 0, [`stats.${name}.lost`]: team !== winningTeam ? 1 : changeWinner ? - 1 : 0 } }, "upsert": true } }) ) ) .then(() => /* whatever continuation here */ ) .catch(e => console.error(e))
在批量操作中为每个数组成员生成一个Array.map()
语句,并将其发送到服务器。当然,另一个变化是您根本不需要"updateOne"
即可读取现有值。您真正需要做的就是使用findOne()
运算符,以increase
$inc
值并将其传递给$inc
的值。注意,这是一般情况下实际应该做的事情,除了避免不必要的异步调用循环外,这里的主要目的是实际使用MongoDB拥有的原子运算符,例如1/-1/0
。从数据库读取数据状态以进行更改是anti-pattern
,最好避免。
正在跳过多个findOneAndUpdate操作
我有一个forEach
循环,在其中查询文档,进行一些简单的数学计算,然后在集合中将updating
一个文档进行下一步。
问题是,很多时候UPDATE
操作中的一些随机操作不会更新文档。我不知道为什么会这样。是因为lock
吗?
我已经尝试在update
操作之前记录日志。数据都是正确的,但是当涉及到update
时,它将完全不会随机更新。在10次迭代中,可以说8次可以正常工作
const name = "foo_game";
players.forEach(({ id, team, username }) => {
let updatedStats = {};
Users.findOne({ id }).then(existingPlayer => {
if (!existingPlayer) return;
const { stats } = existingPlayer;
const existingStats = stats[pug.name];
if (!existingStats) return;
const presentWins = existingStats.won || 0;
const presentLosses = existingStats.lost || 0;
updatedStats = {
...existingStats,
won:
team === winningTeam
? presentWins + 1
: changeWinner
? presentWins - 1
: presentWins,
lost:
team !== winningTeam
? presentLosses + 1
: changeWinner
? presentLosses - 1
: presentLosses,
};
// THE CALCULATIONS ARE ALL CORRECT TILL THIS POINT
// THE UPDATE WIILL RANDOMLY NOT WORK
Users.findOneAndUpdate(
{ id, server_id: serverId },
{
$set: {
username,
stats: { ...stats, [name]: updatedStats },
},
},
{
upsert: true,
}
).exec();
});
});
回答如下:基本上,这里缺少的是findOne()
和findOneAndUpdate()
的异步操作不能保证在foreach()
完成之前完成。对于在其中具有异步操作的循环,使用forEach()
并不是一个不错的选择,但是这里的另一个要点是,由于MongoDB有更好的方法以及在向服务器发送[[one请求中,这是完全不必要的。
bulkWrite()
提供指令数组,而不是“循环”:
bulkWrite()
因此而不是循环,该或decrease当前值。请注意,如果当前在指定路径上未记录任何内容,那么它将创建具有逻辑确定的let server_id = serverId; // Alias one of your variables or just change it's name Users.bulkWrite( players.map(({ id, team, username }) => ({ "updateOne": { "filter": { _id, server_id }, "update": { "$set": { username }, "$inc": { [`stats.${name}.won`]: team === winningTeam ? 1 : changeWinner ? - 1 : 0, [`stats.${name}.lost`]: team !== winningTeam ? 1 : changeWinner ? - 1 : 0 } }, "upsert": true } }) ) ) .then(() => /* whatever continuation here */ ) .catch(e => console.error(e))
在批量操作中为每个数组成员生成一个Array.map()
语句,并将其发送到服务器。当然,另一个变化是您根本不需要"updateOne"
即可读取现有值。您真正需要做的就是使用findOne()
运算符,以increase
$inc
值并将其传递给$inc
的值。注意,这是一般情况下实际应该做的事情,除了避免不必要的异步调用循环外,这里的主要目的是实际使用MongoDB拥有的原子运算符,例如1/-1/0
。从数据库读取数据状态以进行更改是anti-pattern
,最好避免。