我想使用MongoDb描述以下用例:
我想从一个集合中阅读并记住那个特定的时间点。
下次向该集合进行写入时,如果其他文档已添加到该集合中,那么我希望无法编写新文档。
可以在文档上使用timestamp
属性。
这可能吗?
答案 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
值。
从那时起,由应用程序逻辑来处理“冲突”。