Mongodb节点驱动程序 - 当我调用db.close()或幸运时,它真的很重要吗?

时间:2018-06-06 23:31:38

标签: node.js mongodb

我发现db.close()似乎没有关闭,直到所有读取或写入都完成,无论何时调用它。这实际上是我想要的,但我想确保这是预期的行为,而不仅仅是我的幸运。我有一些像这样的代码:

...
{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
  client.close();
}).catch((reason) => { console.log(reason) });

我输出如下:

will close
deleted
inserted

但没有错误,经过进一步测试,实际插入和删除了正确的记录。在文档中我们看到他们在最终的回调中调用db.close(),但是我没有这样做。这可靠吗?我不确定如何重构我的代码以更清楚地表明在insertMany和deleteMany之后发出了close - 也许我应该使用promise.all。

修改 因此,下面的两个答案对于我们如何保证在适当的时间关闭连接是有意义的,Neil Lunn建议使用bulkWrite似乎是出于性能原因的理想选择。为了良好的实践,我可能暂时在我的应用程序中使用bulkWrite路由,但我仍然对我原来的问题感到困惑......

对我来说,似乎上面的代码在client.close()之前发出insertMany和deleteMany,所以我认为mongodb知道有待处理的操作,所以会适当关闭。有人能给我一个关于如何过早调用client.close()的示例场景吗?如果假设任何一个操作中的错误都可能导致client.close()被提前调用,那么我建议添加

{
  collection.insertMany(...).then(()=> { console.log("inserted") })
  collection.deleteMany(...).then(()=> { console.log("deleted") })
}).then(() =>
{
  console.log("will close");
}).catch((reason) => { console.log(reason) })
  .then(() => { client.close() })

2 个答案:

答案 0 :(得分:1)

您需要等待查询完成。您可以通过返回MotherId来执行此操作,这将在查询返回的两个promise都得到满足时解析。此外,使用Promise的.finally()-method确保调用Promise.all([query1, query2]),即使出现错误也是如此。使用当前代码,如果发生错误,则不会调用client.close()

client.close()

答案 1 :(得分:1)

说实话,你不仅仅是“幸运”而且#34;在您致电client.close()之前要解决的行动,但也可能存在潜在的"两个语句并行运行的问题。

理想情况下,您应该使用bulkWrite()并制作一个"单身"请求包含其中包含的两个操作。 "单一请求"也有一个单一的回应"因此等待解决多个承诺没有问题:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

bulkWrite()的默认操作是"有序"并按照它们在"动作"数组中呈现的顺序执行。呈现。此处用于创建insertOne操作的Array.map()实际上正是insertMany()方法在底层驱动程序实现中实际执行的操作。

事实上,所有这些驱动程序方法实际上都会调用基础"批量API"方法作为现代的做事方式。 bulkWrite()明确摘自实际的"批量API"为了优雅地将请求降级到"遗产"连接到MongoDB 2.6之前的MongoDB实例时的API。

另一种方法是" parallel"通过明确设置"ordered": false

来执行
collection.bulkWrite(
  [
  ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
  { "deleteMany": { "filter": filterCondition } }
  ],
  { "ordered": false }
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

故意这意味着所有行动都不依赖于其他人完成"首先"。所以,如果确实你是"插入"你也是"删除"的东西,然后不保证会以任何特定的顺序发生。

除了" parallelism"之外,"ordered": false的一般目的是允许继续"出错"。在这种情况下,所有"批次"实际上已经尝试了动作,并且在异常响应中,您将获得详细信息,告诉您哪个"索引位置"在提供的行动数组中,有任何失败。

然后行为是"""完成"模仿"通过以下Promise.all()调用:

Promise.all([
  collection.insertMany(..., { "ordered": false }).then(()=> { console.log("inserted") }),
  collection.deleteMany(...).then(()=> { console.log("deleted") })
]).then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());

当然,这是在" parallel"但火灾和多次请求"这会产生与服务器来回通信的更大开销。前面例子的目的是避免这种情况,因此是一个更好的选择。

对于"完整性"当然,你总是可以"链"承诺:

  collection.insertMany(...)
    .then(() => console.log("inserted")),
    .then(() => collection.deleteMany(...)
    .then(()=> console.log("deleted"))
    .then(() => console.log("will close"))
    .catch(e => console.error(e))
    .then(() => client.close());

以这种方式"一切"是串行执行,但当然它们都会发出单独的请求。

因此,虽然有办法处理"等待"承诺决议,通常更好地做一次电话"等待#34; Bulk"反而回应。