MongoDb:仅当集合自该时间点以来没有更新的文档时,才在集合中插入文档

时间:2018-07-19 12:58:00

标签: mongodb

我想使用MongoDb描述以下用例:

我想从一个集合中阅读并记住那个特定的时间点。 下次向该集合进行写入时,如果其他文档已添加到该集合中,那么我希望无法编写新文档。 可以在文档上使用timestamp属性。

这可能吗?

3 个答案:

答案 0 :(得分:1)

一个诀窍是使用findAndModify

假设在阅读时,文档的最新时间戳为oldTimestamp

db.collection.findAndModify({
    query: {timestamp: {$gt: oldTimestamp}},
    new: true, // Return modified / inserted document
    upsert: true, // Update if match found, insert otherwise
    update: {
         $setOnInsert: {..your document...}
    }
})

如果在您的读写操作之间插入了另一个文档,则不会插入您的文档。

但是,这不会让您知道是否直接插入了文档。

您应该将返回的文档与建议的文档进行比较,以找出答案。

如果使用nodejs驱动程序,则正确的模式应为:

collection.findAndModify(criteria[, sort[, update[, options]]], callback)

根据example,我们的查询应为:

db.collection('test').findAndModify(
  {timestamp: {$gt: oldTimestamp}}, // query, timestamp is a property of your document, often set as the created time
  [['timestamp','desc']],  // sort order
  {$setOnInsert: {..your document..}}, // replacement, replaces only the field "hi"
  {
      new: true,
      upsert: true
  }, // options
  function(err, object) {
      if (err){
          console.warn(err.message);  // returns error if no matching object found
      }else{
          console.dir(object);
      }
  });
});

答案 1 :(得分:0)

这可以通过在每个文档中使用timestamp属性来实现。您可以查看Mongoose Pre Save path validation hook 。使用此钩子,您可以编写如下内容。

YourSchema.path('timestamp').validate(function(value, done) {
  this.model(YourSchemaModelName).count({ timestamp: {$gt : value} }, function(err, count) {
    if (err) {
        return done(err);
    }
    // if count exists and not zero hence document is found with greater timestamp value
    done(!count);
});
}, 'Greater timestamp already exists');

答案 2 :(得分:0)

听起来像您需要在收藏级别进行某种乐观锁定。我了解您正在编写新文档,但从未更新此收藏集中的现有文档?

您可以在timestamp字段上添加索引,并且您的应用程序将需要跟踪此值的最新版本。然后,在尝试进行新写入之前,您可以使用类似查询的

从集合中查找最新值

db.collection.find({}, {timestamp: 1, _id:0}).sort({timestamp:-1}).limit(1)

使用非常有效的covered query投影最大timestamp值。

从那时起,由应用程序逻辑来处理“冲突”。