我们一直在使用NodeJS和mongo(通过mongoose)来做一个非常简单的save()。我们有一个名为“highlight”的模型,它包含一个引用“response”的ObjectId数组。
这是高亮模型声明的相关部分
var highlightSchema = Schema({
[...]
, responses: [{type: ObjectId, ref: 'Response'}]
[...]
});
我们通过先保存一个Response对象,然后将其推入一个Highlight对象,然后保存Highlight对象,将一个Response插入一个Highlight。非常简单,如下:
Highlight.findOne({[...]}, function(err, highlight) {
var response = new Response({[...]});
response.save(function(err) {
if(!err) {
highlight.responses.push(response)
highlight.save(function(err) {
[...]
})
}
});
});
这大约99%以上的时间完全符合预期。 (注意:您可以放心地假设上面代码中的'highlight'变量确实包含有效的Highlight对象)
然而,我们在高峰时段越来越多地遇到孤立的问题,因为许多同样的要求是同时进行的。在一种情况下,成功创建了响应,但是将一个不同的响应推送到highlight.responses数组中。
这两个响应的时间戳显示它们相隔大约30毫秒创建。除了Highlight对象内的数组内容外,所有内容都完全按照预期创建。
由于我目前也正在深入研究很多操作系统的东西,我首先想到的是这可能是某种同步问题。但是节点是单线程的,我不觉得我对nodejs的事件循环如何工作有很好的理解,我甚至不能完全相信这是问题所在。
如果您有任何想法,或者我能够清楚地解释清楚,请告诉我。我很高兴详细说明。
谢谢!
答案 0 :(得分:4)
您遇到了并发问题。您对模式进行建模的方式无法确保原子性,因此也是您遇到的问题。
避免此类问题并确保原子性的最佳选择是将Responses模型嵌套到Highlights模型中。
这样,您只能通过将Response元素直接推送到Highlight模型的Responses属性中来使用Highlights模型。
这是确保MongoDB原子性的唯一方法。
所以你会有这样的事情:
+----------------------+
| Highlight model |
+----------------------+
| _id 1 |
| |
| property 1: 'abc' |
| property 2: 'bla' |
| property 3: 123 |
| responses:[ |
| +----------------+ |
| | Response _id 1 | |
| +----------------+,|
| | Response _id 2 | |
| +----------------+,|
| | Response _id 3 | |
| +----------------+,|
| | Response _id n | |
| +----------------+]|
+----------------------+
不确定如何使用Mongoose,但在mongo shell中,如果你想用_id ObjectId('1234')添加对Highlight对象的响应,你可以这样做:
db.highlights.update({_id: ObjectId('1234')},{$push:{Responses: {"Your response object"}}});
$push reference from MongoDB documentation
我很确定你必须能够以更简单的方式用Mongoose来完成它,可能只是浏览它的文档。
答案 1 :(得分:1)
要嵌套模型,您可以像这样编写Schema
const ResponseSchema = require('../where your schema file is')
var highlightSchema = Schema({
[...]
, responses: [ResponseSchema]
[...]
});