无法将对象推入数组中的猫鼬

时间:2020-02-26 19:01:00

标签: node.js mongodb mongoose

我有以下模型:

user :{ 
    overall_stats: {
            elo: {
                type: Array,
                default: {
                    date: new Date(),
                    ranking: 1000,
                }
            },
            nrGames: {
                ...
            },
            nrWins: {
                ...
            },
            winRate: {
                ...
            },
    },
   .
   .
   .
}

现在,我想将一个新条目:{ ranking: 1020, date: 2020-02-26T18:39:22.933Z }推送到elo数组。我在下面尝试了不同的版本,但执行该功能后elo属性完全消失了。 nrGames,其他的都正确更新了。

async function updateUserStatsAfterGameInDB(userId, newElo, numberOfGames, numberOfWins, winRate) {
    console.log(newElo);
    return await User.findOneAndUpdate(
        {
            _id: userId  // search query
        },
        {   
            overall_stats : {
                $push: {elo : newElo},
                nrGames : numberOfGames,
                nrWins : numberOfWins,
                winRate : winRate
            }
        },
        {
            new: true,                       // return updated doc
            runValidators: true,              // validate before update
            useFindAndModify: false
        }
    )
}

错误在哪里?

2 个答案:

答案 0 :(得分:1)

您的代码存在某些问题,请尝试以下代码:

async function updateUserStatsAfterGameInDB(userId, newElo, numberOfGames, numberOfWins, winRate) {
    console.log(newElo);
    try {
        return await User.findOneAndUpdate(
            {
                _id: userId  // search query
            },
            {
                $push: { 'overall_stats.elo': newElo },
                'overall_stats.nrGames': numberOfGames,
                'overall_stats.nrWins': numberOfWins,
                'overall_stats.winRate': winRate
            },
            {
                new: true,                       // return updated doc
                runValidators: true,              // validate before update
                useFindAndModify: false
            }
        )
    } catch (error) {
        // Do something on error scenarios
    }
}

注意:

  1. 在猫鼬中,您不需要在更新中显式使用$set,因为它将在内部为您完成。

所以您的代码如下:

{
    overall_stats: {
        $push: { elo: newElo },
        nrGames: numberOfGames,
        nrWins : numberOfWins,
        winRate : winRate
    }
}

转换为:

{
    $set: {
        overall_stats: {
            $push: { elo: newElo },
            nrGames: numberOfGames,
            nrWins : numberOfWins,
            winRate : winRate
        }
    }
}

因此它正在用传入的新对象替换overall_stats对象。以某种方式它可能不会引发任何错误或忽略$push: { elo: newElo }

同样,您也不能使用以下一项:

{   
            $push: {'overall_stats.elo' : newElo},
            overall_stats : {
                nrGames : numberOfGames,
                nrWins : numberOfWins,
                winRate : winRate
            }
  }

因为$push会将元素推到{{1},所以您无法同时对$set对象或其字段进行overall_stats$push }}字段,与此同时elo用新的$set对象完全用新的overall_stats对象替换了overall_stats对象,因此从elo中删除了overall_stats字段!!至少对于不使用聚合管道的.update()操作,它在.update中不会那样工作,它将引发错误,因此,您需要像给定的那样指定每个需要更新的字段以上。

  1. 它不会更新,因为$push是另一个$set运算符,因此它不应位于$set内。

  2. 您需要用async-await包裹任何try-catch以便更好地处理错误。

答案 1 :(得分:1)

$push必须位于update参数的顶级,并且其他更新密钥将与之平行。因此,这将是正确的查询:

User.findOneAndUpdate(
        {
            _id: userId  // search query
        },
        {   
            $push: {'overall_stats.elo' : newElo},
            overall_stats : {
                nrGames : numberOfGames,
                nrWins : numberOfWins,
                winRate : winRate
            }
        },
        {
            new: true,                       // return updated doc
            runValidators: true,              // validate before update
            useFindAndModify: false
        }
    )

$ push的文档:https://docs.mongodb.com/manual/reference/operator/update/push/