Node.js Mongodb节点驱动程序-当我调用db.close()时,这真的很重要吗?还是我运气好?

Node.js Mongodb节点驱动程序-当我调用db.close()时,这真的很重要吗?还是我运气好?,node.js,mongodb,Node.js,Mongodb,我发现db.close()在所有读写操作完成之前都不会关闭,无论何时调用它。这实际上是我想要的,但我想确保这是我想要的行为,而不仅仅是我运气好。我有一些这样的代码: ... { collection.insertMany(...).then(()=> { console.log("inserted") }) collection.deleteMany(...).then(()=> { console.log("deleted") }) }).then(() => {

我发现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似乎是性能方面的理想选择。出于良好实践的考虑,我可能会暂时在我的应用程序中采用批量写入方式,但对于我最初的问题,我仍然有些困惑

在我看来,上面的代码似乎在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() })

您需要等待查询完成。您可以通过返回
Promise.all([query1,query2])
来执行此操作,当查询返回的两个承诺都得到满足时,将解析此问题。此外,使用承诺确保调用
client.close()
,即使出现错误。对于当前代码,如果发生错误,将不会调用
客户端.close()

...
{
  return Promise.all([
    collection.insertMany(...).then(()=> { console.log("inserted") }),
    collection.deleteMany(...).then(()=> { console.log("deleted") })
  ]);
}).then(() => {
  console.log("will close");
}).catch((reason) => {
  console.log(reason);
}).finally(() => {
  client.close();
});

您需要等待查询完成。您可以通过返回
Promise.all([query1,query2])
来执行此操作,当查询返回的两个承诺都得到满足时,将解析此问题。此外,使用承诺确保调用
client.close()
,即使出现错误。对于当前代码,如果发生错误,将不会调用
客户端.close()

...
{
  return Promise.all([
    collection.insertMany(...).then(()=> { console.log("inserted") }),
    collection.deleteMany(...).then(()=> { console.log("deleted") })
  ]);
}).then(() => {
  console.log("will close");
}).catch((reason) => {
  console.log(reason);
}).finally(() => {
  client.close();
});

老实说,在调用
client.close()
之前,您不仅“幸运地”解决了要解决的操作,而且这两条语句并行运行可能存在“潜在”问题

理想情况下,您可以使用并发出一个包含两个操作的“单个”请求。“单一请求”也有“单一响应”,因此等待多个承诺的解决没有问题:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());
  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());
的默认操作是操作按“顺序”执行,并按在“操作”数组中显示的顺序串行执行。这里用来创建
insertOne
操作的方法实际上正是该方法在底层驱动程序实现中实际执行的操作

事实上,所有这些驱动程序方法实际上都调用底层的“批量API”方法,作为现代的处理方式。当连接到MongoDB 2.6之前的MongoDB实例时,显式地从实际的“批量API”抽象出来,以便将请求优雅地降级到“遗留”API

另一种方法是通过显式设置
“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());
这故意意味着没有一项行动依赖于其他人完成“第一”。因此,如果你确实是在“插入”某个你也在“删除”的东西,那么就不能保证它会以任何特定的顺序发生

除了“并行性”之外,
“ordered”:false的一般用途是允许“出错时”继续。在这种情况下,所有“批处理”操作实际上都会被尝试,在异常响应中,您会得到详细信息,告诉您在所提供操作数组中的哪个“索引位置”发生了任何故障

然后通过以下调用在“模仿”中“排序”完成该行为:

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());
这当然是以“并行”方式执行的,但会触发“多个请求”,这会在与服务器的来回通信中产生更大的开销。前面示例的目的是避免这种情况,因此是更好的选择

对于“完整性”,您当然可以“链接”承诺:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());
  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());
这样,“一切”在执行中都是串行的,但当然它们都会发出单独的请求


因此,虽然有办法处理“等待”承诺解决方案,但通常最好是打“一个电话”,然后等待“批量”响应。

老实说,在调用
client.close()
之前,您不仅“幸运地”解决了这些问题,而且还可能存在“潜在问题”两条语句并行运行时出现问题

理想情况下,您可以使用并发出一个包含两个操作的“单个”请求。“单一请求”也有“单一响应”,因此等待多个承诺的解决没有问题:

collection.bulkWrite(
  [
    ...listOfInsertDocuments.map(document => ({ "insertOne": { document } })),
    { "deleteMany": { "filter": filterCondition } }
  ]
)
.then(() => console.log("will close"))
.catch(e => console.error(e))
.then(() => client.close());
  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());
的默认操作是操作按“顺序”执行,并按在“操作”数组中显示的顺序串行执行。这里用来创建
insertOne
操作的方法实际上正是该方法在底层驱动程序实现中实际执行的操作

事实上,所有这些驱动程序方法实际上都调用底层的“批量API”方法,作为现代的处理方式。当连接到MongoDB 2.6之前的MongoDB实例时,显式地从实际的“批量API”抽象出来,以便将请求优雅地降级到“遗留”API

另一种方法是通过显式se“并行”执行