最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

正在跳过多个findOneAndUpdate操作

IT培训 admin 2浏览 0评论

正在跳过多个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()
因此而不是循环,该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

decrease当前值。请注意,如果当前在指定路径上未记录任何内容,那么它将创建具有逻辑确定的$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()
因此而不是循环,该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

decrease当前值。请注意,如果当前在指定路径上未记录任何内容,那么它将创建具有逻辑确定的$inc值并将其传递给$inc的值。注意,这是一般情况下实际应该做的事情,除了避免不必要的异步调用循环外,这里的主要目的是实际使用MongoDB拥有的原子运算符,例如1/-1/0。从数据库读取数据状态以进行更改是

anti-pattern

,最好避免。

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论