我有一个nodeJS服务器,它维护一个MongoDB和一个客户端,它在JSON中发送一个带有buildName变量的post请求。
我要做的是设置一个事件监听器,当具有与客户端发送的buildName匹配的字段的mongoDB文件被更新或创建时触发该事件监听器。多个客户端可以正在侦听,如果更新或创建了包含与其传入的相同buildName的文档,则必须通知它。
我尝试使用这种方法进行轮询,其中我的客户端只是坐在一个while循环中并不断询问是否有更新,但是,我遇到性能问题所以我切换到事件监听器。
我尝试了几种不同的方法来设置回调,当我的客户端发送其post请求时,只要文档更新就会调用该请求,然后将更新的mongodb doc作为res.json
发送。我正在使用的一个是mongoose-trigger npm模块,它允许我为创建和更新设置事件监听器。
我还在这里查看可能的解决方案,这些解决方案让我mongoose-trigger获取在创建和更新时触发的事件,但仍然无法找到满足使用此触发来触发对发布请求的响应的答案。
以下是创建触发事件对象的代码片段:
10 const Events = trigger(buildSchema, {
11 events: {
12 create: {
13 select: 'logFile'
14 },
15 update: {
16 select: 'logFile'
17 }
18 },
19 debug: true
20 });
21
22 module.exports = {
23 Build: mongoose.model('build', buildSchema),
24 Events: Events
25 };
上面的代码片段设置了mongoose-trigger npm模块,然后在我的server.js中我在我的帖子路径中使用它,如下所示:
11 const Model = require('./build');
12 mongoose.connect('mongodb://vcdep-db/builds');
13
14 app.post('/get_build', function(req, res) {
15 const buildName = req.body.buildName;
16 console.log(buildName);
17 Model.Events.on('create', data => {
18 Model.Build.findById(data._id, function(err, build) {
19 if (err) console.error(err);
20
21 console.log("Created model");
22 if (build.buildName === buildName)
23 {
24 console.log("Document got created", build.buildName);
26 res.json(build);
27 }
28
29 });
30 });
31 Model.Events.on('update', data => {
32 Model.Build.findById(data._id, function(err, build) {
33 if (err) console.error(err);
34
35 console.log("Updated model");
36 if (build.buildName === buildName)
37 {
38 console.log("Document got updated", build.buildName);
40 res.json(build);
41 }
42
43 });
44 });
45 });
上面的代码第一次更新或创建文档时工作,但是,当我执行相同的过程时,我得到一个Error: Can't set headers after they are sent.
我相信这是因为mongoose-trigger设置的监听器不会被删除我发送res.json(build)
所以当同一文档再次更新时,它会尝试从先前的客户端回调中执行相同的res.json
,这会触发该错误。
我考虑在这里删除事件监听器,看看mongoose-trigger是否允许这样的东西,但尚未找到解决方案。
我相信一旦发送了响应,我就能解除触发器的绑定,它应该修复错误,但我可能错了。如果有人可以提供帮助,我会非常感激!
另外,我并不喜欢使用mongoose-trigger,所以如果有更好的方法来监听mongoDB更新或创建此类事件我非常愿意将其更改为其他内容。
答案 0 :(得分:1)
一旦调用了其中一个回调对,就需要删除它们。为了能够这样做,你不能使用任何功能,但必须使用命名函数:
app.post('/get_build', function(req, res) {
const buildName = req.body.buildName;
console.log(buildName);
function onCreate(data) {
Model.Build.findById(data._id, function(err, build) {
if (err) console.error(err);
console.log("Created model");
if (build.buildName === buildName) {
console.log("Document got created", build.buildName);
// clean up the event listeners
Model.Events.removeListener('create', onCreate);
Model.Events.removeListener('update', onUpdate);
res.json(build);
}
});
}
function onUpdate(data) {
Model.Build.findById(data._id, function(err, build) {
if (err) console.error(err);
console.log("Updated model");
if (build.buildName === buildName) {
console.log("Document got updated", build.buildName);
// clean up the event listeners
Model.Events.removeListener('create', onCreate);
Model.Events.removeListener('update', onUpdate);
res.json(build);
}
});
}
Model.Events.on('create', onCreate);
Model.Events.on('update', onUpdate);
});
但这仍然是一个糟糕的设计,更好的方法是使用socket.io
或类似的东西。