Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 以原子方式更新数组项 基本问题:_Javascript_Node.js_Mongodb_Mongoose_Mongodb Query - Fatal编程技术网

Javascript 以原子方式更新数组项 基本问题:

Javascript 以原子方式更新数组项 基本问题:,javascript,node.js,mongodb,mongoose,mongodb-query,Javascript,Node.js,Mongodb,Mongoose,Mongodb Query,如何以原子方式检查文档的子数组以查看条目是否存在,如果存在则更新,如果不存在则添加?我还想根据第一次操作的结果,对计数器进行原子调整(使用$inc) 详细说明: 我正在尝试编写一种方法,为任意mongodb文档提供原子“向上投票”或“向下投票”功能 我希望发生以下情况: 向给定模式添加“投票”和“voteScore”项 “投票”是由投票类型(向上或向下)和投票人的用户ID组成的对象数组 “voteScore”是所有投票的运行总和(+1表示赞成票,-1表示反对票) 我试图实现的逻辑是: 当用

如何以原子方式检查文档的子数组以查看条目是否存在,如果存在则更新,如果不存在则添加?我还想根据第一次操作的结果,对计数器进行原子调整(使用
$inc

详细说明: 我正在尝试编写一种方法,为任意mongodb文档提供原子“向上投票”或“向下投票”功能

我希望发生以下情况:

  • 向给定模式添加“投票”和“voteScore”项
  • “投票”是由投票类型(向上或向下)和投票人的用户ID组成的对象数组
  • “voteScore”是所有投票的运行总和(+1表示赞成票,-1表示反对票)
我试图实现的逻辑是:

  • 当用户进行向上或向下投票时,“voteScore”将使用原子
    $inc
    操作符进行相应更新,并使用该用户的ID和投票类型向数组中添加新投票
  • 当用户更改其投票时,voteScore将自动更新,投票将从数组中删除(如果
    voteType
    “无”
    ),或者voteType将就地更新以反映更改
我该怎么做呢?我假设我将不得不使用ether
document.update()
model.findOneAndUpdate()
,因为传统的方法(后跟
save()
)不会是原子的

到目前为止,我有以下代码,但它不起作用:

var mongoose = require('mongoose');

var voteTypes = ['up', 'down'];
var voteSchema = new mongoose.Schema({
  userId: { type: Schema.Types.ObjectId, ref: 'User',  },
  voteType: { type: String, enum: voteTypes }
});
exports.schema = voteSchema;

exports.plugin = function votesPlugin(schema, options) {
  schema.add({ voteScore: Number });
  schema.add({ votes: [voteSchema] });
  
  schema.methods.atomicVote = function(args, callback) {
    var item = this;
    var voteType = (args.voteType && args.voteType.toLowerCase()) || 'none';
    
    var incrementScore, query;

    switch (voteType) {
      case 'none':
        incrementScore = -voteTypeValue(voteRemoved.voteType);
        query = this.update({ $inc: {voteScore: incrementScore}, $pull: { votes: { userId: args.userId } } });
        break;
      case 'up':
      case 'down':
        var newVoteVal = voteTypeValue(args.voteType);
        if (/* Vote does not already exist in array */) {
          incrementScore = newVoteVal;
          query = this.update({$inc: {voteScore: incrementScore}, $addToSet: { userId: args.userId, voteType: args.voteType });
        } else {
          var vote = /* existing vote */;
          if (vote.voteType === args.voteType) return callback(null); // no-op
          var prevVoteVal = voteTypeValue(vote.voteType);
          incrementScore = (-prevVoteVal) + newVoteVal;
          vote.voteType = args.voteType;
          // This likely won't work because document.update() doesn't have the right query param
          // to infer the index of '$'
          query = this.update({$inc: {voteScore: incrementScore}, $set: { 'votes.$': { userId: args.userId, voteType: args.voteType } });
        }
        break;
      default:
        return callback(new Error('Invalid or missing "voteType" argument (possible values are "up", "down", or "none").'));
    }
    
    query.exec(callback);
  };
};

function voteTypeValue(voteType) {
  switch (voteType) {
    case 'up': return 1;
    case 'down': return -1;
    default: return 0;
  }
}

要以原子方式进行此操作,最好将数组分离以获得“向上/向下”投票。通过这种方式,您可以同时从每个字段中选择一个或多个字段。这主要是因为MongoDB无法在文档中同一字段路径的一次更新中执行这些操作。尝试这样做会导致错误

简化的模式表示可能如下所示:

var questionSchema = new Schema({
    "score": Number,
    "upVotes": [{ type: Schema.Types.ObjectId }],
    "downVotes": [{ type: Schema.Types.ObjectId }]
]);

module.exports = mongoose.model( 'Question', questionSchema );
这是一个通用的表示,所以不要太字面化,但主要的一点是两个数组

在处理“upvote”时,您真正需要做的就是确保您没有添加到“upvotes”数组中该“用户”已经存在的位置:

Question.findOneAndUpdate(
    { "_id": question_id, "upVotes": { "$ne": user_id } },
    {
        "$inc": { "score": 1 },
        "$push": { "upVotes": user_id },
        "$pull": { "downVotes": user_id }
    },
    function(err,doc) {

    }
);
而反过来处理“否决票”:

逻辑上的扩展是,只需从两个数组中“提取”即可取消所有投票。但是,您确实可以对此“聪明”,并在应用程序中维护“状态”信息,以便“知道”您是否也在增加或减少“分数”

所以对于我来说,我会这样做,并且在发送响应时也会处理“数组”结果,只是过滤掉当前“用户”的状态信息,这样你就可以在取消请求时做出明智的选择,甚至不向服务器发送请求,因为该用户可能已经投了“向上投票”或“向下投票”


还请注意,如果没有查询as,则此处不是一个选项,因为它独立于其他运算符进行操作。因此,您不希望“选择”一个对更新无效的文档。

要以原子方式执行此操作,最好将数组分离以进行“上/下”投票。通过这种方式,您可以同时从每个字段中选择一个或多个字段。这主要是因为MongoDB无法在文档中同一字段路径的一次更新中执行这些操作。尝试这样做会导致错误

简化的模式表示可能如下所示:

var questionSchema = new Schema({
    "score": Number,
    "upVotes": [{ type: Schema.Types.ObjectId }],
    "downVotes": [{ type: Schema.Types.ObjectId }]
]);

module.exports = mongoose.model( 'Question', questionSchema );
这是一个通用的表示,所以不要太字面化,但主要的一点是两个数组

在处理“upvote”时,您真正需要做的就是确保您没有添加到“upvotes”数组中该“用户”已经存在的位置:

Question.findOneAndUpdate(
    { "_id": question_id, "upVotes": { "$ne": user_id } },
    {
        "$inc": { "score": 1 },
        "$push": { "upVotes": user_id },
        "$pull": { "downVotes": user_id }
    },
    function(err,doc) {

    }
);
而反过来处理“否决票”:

逻辑上的扩展是,只需从两个数组中“提取”即可取消所有投票。但是,您确实可以对此“聪明”,并在应用程序中维护“状态”信息,以便“知道”您是否也在增加或减少“分数”

所以对于我来说,我会这样做,并且在发送响应时也会处理“数组”结果,只是过滤掉当前“用户”的状态信息,这样你就可以在取消请求时做出明智的选择,甚至不向服务器发送请求,因为该用户可能已经投了“向上投票”或“向下投票”


还请注意,如果没有查询as,则此处不是一个选项,因为它独立于其他运算符进行操作。因此,您不想“选择”一个对更新无效的文档。

问题是什么?我如何原子化地执行此操作?啊,好吧,这几乎在您的帖子中丢失了。MongoDB并没有提供太多的锁定功能——我相信这样做的方法是定义一个实际执行该操作的JS函数——但我甚至不确定这是否会给您原子性然而,如果你能设法将它塞进一个update(),那将是原子的。您能否将这个问题简化为一个MongoDB操作,您正试图将其与一个示例文档结合使用?是的,我相信可以在一个
update()
(或者至少在一个
update()
中使用大多数逻辑,然后希望Mongoose的版本控制能够防止其他可能的争用情况)。我只是不太熟悉猫鼬所揭露的潜在的猫鼬的东西,所以我希望有更多的专业人士能插话,告诉我这样的东西是如何工作的。问题是什么?我如何做到原子化?啊,好吧,这几乎在你的帖子中消失了。MongoDB并没有提供太多的锁定功能——我相信这样做的方法是定义一个实际执行该操作的JS函数——但我甚至不确定这是否会给您原子性然而,如果你能设法将它塞进一个update(),那将是原子的。你能