node.js - save() 回调中的数据与数据库之间的差异

标签 node.js sails.js waterline

我正在 sails.js 中开发多人纸牌游戏,并且遇到了有关 save() 的问题。我正在查询 3 条记录,更改它们的一些关联属性,然后按顺序保存它们。问题在于,作为参数传递给传递给 save(cb) 的函数的已保存数据的临时副本与数据库上的信息不同。

我正在使用两个相关模型:卡牌,具有“附件”属性,即卡牌记录的集合;以及玩家,具有“手牌”和“ rune ”属性,它们都是卡牌记录的集合。

该操作采用以下参数:

req.body.thiefId 和 req.body.victimId 是玩家记录的 id。 req.body.jackId和req.body.targetId是Card记录的id。

req.body.pNum是玩家排序后,小偷玩家的索引。 sortPlayers[req.body.pNum] 是小偷玩家,sortPlayers[(req.body.pNum + 1) % 2] 是受害玩家。

该 Action 从小偷手中取出一张 J,将其放入目标卡牌的附件集合中(从受害玩家的 rune 集合开始),从受害玩家的 rune 集合中移除目标卡牌,并将目标卡添加到小偷玩家的 rune 集合中。然后记录全部保存。本质上, jack 是从一个玩家(小偷的)手上玩的,位于受害玩家 rune 中的一张牌的“顶部”,然后目标牌被移动到小偷的 rune 中。

问题在于两个玩家的“ rune ”属性没有正确保存在数据库中。无论哪个玩家是受害者,都将目标卡牌保留在他们的 rune 集合中,而小偷玩家不会将目标卡牌添加到他们的 rune 集合中。 jack 卡被正确地从小偷玩家的手牌中移除并添加到目标卡的附件中。真正奇怪的是 save() 返回的数据的本地副本是正确的!记录savedP0和savedP1始终具有正确的 rune 集合,但检查localhost:1337/player处的服务器显示数据库尚未保留更改。这怎么可能?我对 save() 方法的理解是,传递给传递给 save() 的函数的记录参数始终是数据库实际记录内容的精确副本。

这是导致问题的操作的一个相对简单的示例:

    jackBug: function (req, res) {
        Player.find([req.body.thiefId, req.body.victimId]).populateAll().exec(function (erro, players) {
            Card.findOne(req.body.targetId).populate('attachments').exec(function (err, targetCard) {
                //Sort the players according to their 'pNum' attribute
                var playerSort = sortPlayers(players);

                //Remove the jack from the theif player's hand and add the target card to the thief player's points
                playerSort[req.body.pNum].runes.add(targetCard.id);
                playerSort[req.body.pNum].hand.remove(req.body.jackId);

                //Remove the target card from the victim player's points
                playerSort[(req.body.pNum + 1) % 2].runes.remove(targetCard.id);

                //Add the jack card to the target card's attachments
                targetCard.attachments.add(req.body.jackId);


                    playerSort[0].save(function (e, savedP0) {
                        playerSort[1].save(function (e6, savedP1) {
                            targetCard.save(function(e7, savedTarget) {
                                console.log("\nsavedP0:");
                                //This data is always correct, even though the server is wrong
                                console.log(savedP0);
                                console.log("\n\nsavedP1");
                                //This data is also always correct, but it also disagrees with the server
                                console.log(savedP1);
                            });
                        });
                    });
            });
    });
},

发生了什么事?数据库如何不同意传递给 save() cb 的记录?

编辑:这是该操作的重构版本,它不会调用 sortPLayer(players),希望避免异步问题。返回到传递给 save() 的 cb 的记录仍然正确,而数据库仍然错误。

    jackBug: function (req, res) {
        Player.find([req.body.thiefId, req.body.victimId]).populateAll().exec(function (erro, players) {
            Card.findOne(req.body.targetId).populate('attachments').exec(function (err, targetCard) {

                if (players[0].id === req.body.thiefId) {
                    var thiefIndex = 0;
                    var victimIndex = 1;
                } else if (players[1].id === req.body.thiefId) {
                    var thiefIndex = 1;
                    var victimIndex = 0;
                }

                //Remove the jack from the theif player's hand and add the target card to the thief player's points
                players[thiefIndex].runes.add(targetCard.id);
                players[thiefIndex].hand.remove(req.body.jackId);

                //Remove the target card from the victim player's runes
                players[victimIndex].runes.remove(targetCard.id);

                //Add the jack card to the target card's attachments
                targetCard.attachments.add(req.body.jackId);


                    players[0].save(function (e, savedP0) {
                        players[1].save(function (e6, savedP1) {
                            targetCard.save(function(e7, savedTarget) {
                                console.log("\nsavedP0:");
                                console.log(savedP0);
                                console.log("\n\nsavedP1");
                                console.log(savedP1);
                            });
                        });
                    });
            });
    });
},

最佳答案

好吧,我已经明白了!出现了两个问题:首先,我对 .add()、.remove() 和 .save() 如何协同工作感到困惑。根本问题是每个玩家的 rune 集合与各种卡牌记录是一对多关联,并且我在两个不同玩家的 rune 集合上调用 .add() 和 .remove() ,并通过这两个调用移动同一张卡。这不起作用,因为这两个集合都是通过卡记录上的相同外键关联的。我不明白的是, .remove() 实际上是提示一个 cb (在调用 .save() 时触发),该 cb 转到关联的(卡)记录并删除已删除记录(卡)所在集合中的记录(玩家)的外键。这意味着我的 .add() 调用被 .remove() 调用覆盖,因为 .add() 正在实例化从卡到玩家的外键,然后 .remove() 正在删除该外键,即使它不再指向我试图从其 rune 集合中删除卡的玩家。解决方法非常简单:根本不调用 .remove() ,因为使用 .add() 将卡插入一个玩家的 rune 集合中会通过覆盖外键自动将其从另一个玩家的 rune 中删除。

然而,这引起了我的注意,这是第二个间接问题,即 .save() 回调中返回的记录并不总是与对数据库所做的更改保持一致。我认为问题在于 .save() 根据 .add() 和 .remove() 调用返回了一个填充的玩家记录,该记录与我们期望的数据库外观相匹配,但它没有考虑到我使用的错误逻辑,因此它返回了一条看起来正确的记录,即使数据库是错误的。这是正在发生的事情吗?是否应该调整 .save() 以始终返回数据库存储的内容?

通过利用 Bluebird.js 的 Promise,我已经能够使 .save() 返回的记录与数据库匹配(即使 .add 和 remove 调用相互覆盖)。可能有更好的方法来做到这一点,但我为每个 .find() 做出一个新的 promise ,当 promise 履行时返回找到的记录,使用 Promise.all() 等待找到所有记录,然后再继续逻辑,然后使用 .spread() 执行所有保存,并在调用publishUpdate之前等待它们返回。似乎没有其他人遇到过我的愚蠢问题,所以这种模式可能对其他人没有帮助,但我现在要关闭这个问题,因为它似乎已经全部弄清楚了!

关于node.js - save() 回调中的数据与数据库之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31347281/

相关文章:

javascript - 如何在 NodeJS 和 Vuejs 中显示主页上的帖子总数

node.js - 如何使用 Node.js 响应命令行提示符

node.js - 如何使用 Sails.js v1 中的 .find() 方法进行不区分大小写的搜索

node.js - 如何在 sails 模型中使用日期时间

node.js - sails Js : how do I save collections with particular fields to the mongo db via waterline

node.js - Mongoose 排序并每个字段只获取一个

javascript - 变量的范围和更改 Node 中的全局变量

node.js - 我应该使用 Sails.js 和 Stormpath 来整合 session 管理吗?

node.js - 如何使用 SailsJS Waterline update() 方法将数据添加到集合行中的两个字段

validation - 如何知道哪个属性称为水线验证规则?