如何以原子方式将一个顺序增加的id添加到一组名称/ id对

时间:2014-06-06 16:52:34

标签: mongodb

我需要将顺序增加的id分配给一组名称。这归结为:

包含要生成的下一个ID的字段:curId

包含名称/值对的集myset,其中值为id,名称为名称

问题:

我需要原子地:
1.检查myset是否包含' name'。如果没有,
2.使用$ inc生成新的id 3.在myset中插入名称/ ID对。

我无法在mongodb中找到一种方法,至少在没有引入竞争条件的情况下。建议欢迎。

更新

示例文档(它应该是什么样子)。

在添加' c':

之前
{

    "mySet": [
        {
            "name": 'a',
            "value" : 1
        },
        {
            "name": 'b',
            "value" : 2
        }
    ]
}

添加' c'。返回3,因为这是分配给' c'。

的ID
{

    "mySet": [
        {
            "name": 'a',
            "value" : 1
        },
        {
            "name": 'b',
            "value" : 2
        },
        {
            "name": 'c',
            "value" : 3
        }
    ]
}

尝试添加' c'再次。 没有任何事情发生,因为' c'已经存在了。但是' 3'返回,因为这是' c'。

的ID

2 个答案:

答案 0 :(得分:1)

这是一种简单的方法,它涉及维护与nextId相对应的计数器 in 使用此集合的文档,它涉及一个简单的查找查询和更新。从空文档开始:

{ 
  "curId": 1,
  "mySet" : [  ]
}

想要添加下一个"名称"的过程(变量名称)执行以下两个操作:

var Name = "a";
var curId = db.coll.findOne({"mySet.name":{"$ne":Name}},{"_id":0,"curId":1}).curId;

/* curId variable is now 1 */
var result = db.coll.update(
    { "mySet.name" : {"$ne":Name}, "curId":curId },
    { "$push": {"mySet" : {"name":Name,"value":curId} }, "$inc":{"curId":1} }
);

if (result.nModified == 0) {
   print("We lost - someone else must have gotten there first");
}

这里的关键部分是:

  1. 查找查询和更新查询的条件是Name尚未进入mySet数组"名称"。

  2. 更新查询还包含先前读取的curId值,以确保自我们阅读以来没有其他线程更新过该记录。

  3. curId字段仅在成功$push时增加到数组而不是上一次读取curId - 直到我们成功使用{ {1}}值可用,我们不想增加它。

答案 1 :(得分:0)

db.counter.insert({"_id": "myCollectionName", "count": 1})

这会创建一个计数器集合。运行查找并修改以增加它。 http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/此操作是原子操作,不会导致竞争条件。将结果用作新ID。

编辑:道歉,没有意识到所有3个都需要是原子的。使用$ push(http://docs.mongodb.org/manual/reference/operator/update/push/)。此操作不保证数组将按顺序排列(id为2可能会在id 1之前将其放入数组中)但是,如果您使用直接更新而丢失数组元素的可能性是不存在的。使用$ push与findandmodify(http://docs.mongodb.org/manual/reference/method/db.collection.findAndModify/)结合使用,这也是原子的。