Promise 和 upserting 到数据库

Posted

技术标签:

【中文标题】Promise 和 upserting 到数据库【英文标题】:Promises and upserting to database in bulk 【发布时间】:2017-08-29 20:16:30 【问题描述】:

我目前正在解析一个 js 对象列表,这些对象被一个一个地插入到数据库中,与 Node.js 大致类似:

return promise.map(list,
    return parseItem(item)
        .then(upsertSingleItemToDB)
    ).then(all finished!)

问题在于,当列表变得非常大(约 3000 个项目)时,并行解析所有项目会占用大量内存。使用 promise 库添加并发限制真的很容易,并且不会以这种方式耗尽内存(when/guard)。

但我也想优化 db upserts,因为 mongodb 提供了 bulkWrite 函数。由于一次解析和批量写入所有项目是不可能的,所以我需要将原始对象列表拆分为较小的集合,这些集合使用 Promise 并行解析,然后该集合的结果数组将传递给 Promisified bulkWrite。如果列表项,这将在剩余的集合中重复。

我很难思考如何构建较小的承诺集,以便我一次只执行一组 parseSomeItems-BulkUpsertThem(类似于 Promise.all([set1Bulk][set2Bulk]) ,其中 set1Bulk 是另一个并行解析器 Promises 数组?),任何伪代码帮助将不胜感激(但我会在何时使用)。

【问题讨论】:

【参考方案1】:

如果使用 mongoose 和底层的 nodejs-mongodb-driver,它可能看起来像这样:

const saveParsedItems = items => ItemCollection.collection.bulkWrite( // accessing underlying driver
   items.map(item => (
      updateOne: 
           filter: id: item.id, // or any compound key that makes your items unique for upsertion
           upsert: true,
           update: $set: item // should be a key:value formatted object
      
   ))
);


const parseAndSaveItems = (items, offset = 0, limit = 3000) =>  // the algorithm for retrieving items in batches be anything you want, basically
  const itemSet = items.slice(offset, limit);
  
  return Promise.all(
    itemSet.map(parseItem) // parsing all your items first
  )
    .then(saveParsedItems)
    .then(() => 
      const newOffset = offset + limit;
      if (items.length >= newOffset) 
        return parseAndSaveItemsSet(items, newOffset, limit);
      
      
      return true;
    );
;

return parseAndSaveItems(yourItems);

【讨论】:

啊,当然是递归!我的大脑一直在兜圈子,试图做出一些长长的 Promise 链......谢谢大家,这正是我正在寻找的 【参考方案2】:

第一个答案看起来很完整。然而,这里有一些其他的想法浮现在脑海中。

作为一种解决方法,您可以在执行下一个写操作之前在写操作的回调中调用超时函数。这可以让您的 CPU 和内存在调用之间中断。即使您在调用之间增加一毫秒,如果您总共有 3000 个写入对象,那也只会增加 3 秒。

或者您可以分割您的 insertObjects 数组,并将它们发送到自己的批量写入器。

【讨论】:

以上是关于Promise 和 upserting 到数据库的主要内容,如果未能解决你的问题,请参考以下文章

Upsert 和跟踪旧值

将集合映射到 upsert 到数据库中。如何批量更新插入?

使用 jOOQ UPserting 到 Postgres 表时返回更新的行数

在Salesforce中Upsert批量与批量Upsert

Android 房间持久性库:Upsert

Spring数据休眠upsert事务错误@TransactionalEventListener和@Transactinal