簡體   English   中英

如何在批量導入中使用 sequelize findorcreate?

[英]How to use sequelize findorcreate in bulk import?

我正在嘗試在 CSV 導入中使用findOrCreate函數來防止使用相同的電子郵件地址創建多個用戶,但它不起作用。

我將 CSV 文件中的所有行導入內存:

importableCsvRows.forEach(row => importData(row))

然后我遍歷每一行來導入一個用戶:

function importData (row) {
  const name = row[0]
  const email = row[1]
  addUser(name, email)
}

在 addUser 函數中,我使用 findOrCreate:

function addUser (name, email) {
  return new Promise(function (resolve, reject) {
    const user = models.users.findOrCreate({
      where: {email: email},
      defaults: { email: email, name: name }
    })
    .then(u => {
      return resolve(u)
    })
    .catch(err => {
      console.log('ERROR', err)
      return reject(err)
    })
  })
}

問題是多個事務開始了,因為 findOrCreate 是異步的,所以在第一行完成處理之前,下一行開始。

在您的forEach您需要等到 db 事務完成后再開始導入下一個用戶。

最簡單的方法是等待importData函數:

async function importData (row) {
  const name = row[0]
  const email = row[1]
  try {
    await addUser(name, email)
  } catch(err) {
    //console.log?
  }
}

此外,在addUser :無需返回您自己的 Promise。 只需返回承諾findOrCreate返回:

function addUser (name, email) {
    return models.users.findOrCreate({
      where: {email: email},
      defaults: { email: email, name: name }
    })
  })
}

由於findOrCreate沒有本地批量替代findOrCreate ,我們必須手動完成(正如您已經嘗試過的那樣)。

Promise.all + map在這里很有幫助。 Promise.all並行運行所有請求,並充當屏障,等待所有承諾完成。

這是一個簡單的工作代碼示例:

async function addUserRows(userRow) {
  return await Promise.all(
    rows.map(addUserRow)
  );
}
async function addUserRow(row) {
  const [name, email] = row;
  return addUser(name, email)
}
async function addUser (name, email) {
  return models.users.findOrCreate({
    where: {email},
    defaults: { email, name }
  });
}

如果我有很多行怎么辦?

如果您改用 Bluebird 的Promise.map ,事情會變得簡單一些,您甚至可以限制正在進行的承諾的最大並發數量,如果您有很多行,這絕對是可取的。

但是,更高級的方法是使用兩個順序查詢:

  1. 第一個查詢獲取所有丟失的條目。
  2. 第二個查詢寫入所有丟失的條目(使用bulkCreate
  3. 如果您有太多行,請將大集合切成較小的批次並重復,直到發送所有批次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM