0

我希望我有一个大笨蛋时刻。但这是我在一个刮擦场景中的情况;

我希望能够刮过多台机器和内核。每个站点,我有不同的Front页面,我会抓取(例如,对于站点 stackoverflow,我将有 fronts stackoverflow.com/questions/tagged/javascript 和 stackoverflow.com/questions/tagged/nodejs)。

可以article在每篇文章中出现Front,当我发现一篇文章时,Article如果 url 未知,我想创建一个,如果它已知,我想在if未知中输入一个Front条目,否则将 my 插入到适当的.article.discoverFrontFrontDiscoveryFront

这是我的模式;

FrontDiscovery = new Schema({
    _id         :{ type:ObjectId, auto:true },
    date        :{ type: Date, default:Date.now},
    dims        :{ type: Object, default:null},
    pos         :{ type: Object, default:null}
});

Front = new Schema({
    _id         :{ type:ObjectId, auto:true },
    url         :{type:String}, //front
    found       :[ FrontDiscovery ]
});

Article = new Schema({
    _id         :{ type:ObjectId, auto:true },
    url         :{ type: String , index: { unique: true } },
    site        :{ type: String },
    discover:[ Front]
});

我认为我最终会遇到的问题是竞争条件。当两个工作运行者(并行)找到相同的(以前未知的)文章并创建一个新的。是的,我有一个唯一的索引,可以这样处理 - 恕我直言,非常不雅。

但让我们走得更远;当 - 无论出于何种原因 - 我的 2 名工作人员同时刮擦同一个前线,并且都注意到Front还没有条目并创建一个新的添加FrontDiscovery,我将以两个条目结束相同的Front

你有什么策略来规避这种情况?findByIdAndUpdate 与 upsert:true 分别为每个文档?如果是这样,我怎样才能只将某些内容推送到嵌入式文档集合而不同时覆盖其他所有内容,但如果尚未创建它仍会创建默认值?

感谢您在指导我正确方向方面的任何帮助!我真的希望我有一个巨大的brainfart..

4

1 回答 1

1

更新upsert=true可用于执行原子“插入或更新”(http://docs.mongodb.org/manual/core/update/#update-operations-with-the-upsert-flag)。

例如,如果我们想确保 Front 集合中具有特定属性的文档url只插入一次,我们可以运行如下代码:

db.Front.update(
    {url: 'http://example.com'},
    {$set: {
       url: 'http://example.com'},
       found: true
    }
)

MongoDB 中对单个文档的操作始终是原子的。如果您进行跨越多个文档的更新,则不能保证原子性。在这种情况下,你可以问自己:我真的需要原子操作吗?如果答案是否定的,那么您可能会找到处理可能不一致的数据的方法。如果答案是肯定的并且您想坚持使用 MongoDB,请查看两阶段提交上的设计模式。

于 2013-07-21T17:33:17.137 回答