save()回调中的数据与数据库

时间:2015-07-10 17:55:12

标签: node.js sails.js waterline

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

我使用了两个相关的模型:卡片,它们具有“附件”属性,即卡片记录的集合,以及具有“手”和“符文”属性的播放器,它们都是卡片记录的集合。

该操作采用以下参数:

req.body.thiefId和req.body.victimId是玩家记录的ID。 req.body.jackId和req.body.targetId是卡片记录的ID。

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

该动作从小偷的手中拿出一个杰克,将其放入目标卡的附件集合中(从受害者玩家的符文集合开始),从受害者玩家的符文集合中移除目标卡并添加目标卡小偷玩家的符文集。然后记录全部保存。从本质上讲,杰克是从一个玩家的(小偷)手中,在受害者玩家的符文中的一张牌的“顶部”上玩,然后目标牌被移动到小偷的符文。

问题是两个玩家的'符文'属性没有在数据库中正确保留。无论哪个玩家是受害者,都将目标卡保存在他们的符文集合中,并且小偷玩家不会将目标卡添加到他们的符文集合中。插孔卡从小偷播放器的手集中正确移除并添加到目标卡的附件中。真正奇怪的是save()返回的数据的本地副本是正确的!记录savedP0和savedP1始终具有正确的符文集合,但是检查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(玩家),希望避免异步性问题。返回到传递给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);
                            });
                        });
                    });
            });
    });
},

1 个答案:

答案 0 :(得分:0)

好的,我已经弄明白了!有两个问题正在发生:首先,我对.add(),. remove()和.save()如何协同工作感到困惑。根本问题在于每个玩家的符文集合与各种卡片记录的一对多关联,我在两个不同的地方调用.add()和.remove()玩家&#39;符文集合并在两次调用时移动相同的卡片。这不起作用,因为这两个集合都通过卡片记录上的相同的外键相关联。我没有理解的是.remove()实际上确实是一个cb(当调用.save()时被触发)转到关联的(卡)记录和将外键删除到已删除记录(卡)所在的集合中的记录(播放器)。这意味着我的.adove()调用正在覆盖我的.add()调用,因为.add()正在将一个外键从卡实例化到播放器,然后.remove()正在删除该外键,<强大>即使它不再指向我试图删除卡片的符文集合。修复非常简单:根本不要调用.remove(),因为使用.add()将卡片推入一个玩家的符文集会自动将其从其他播放器中移除#s;通过覆盖外键来符文。

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

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