【发布时间】:2015-07-23 11:18:14
【问题描述】:
我试图了解一些不太重要的承诺/异步用例。在我目前正在处理的一个示例中,我有一个从 knex 查询(thenable 数组)返回的书籍数组,我希望将其插入数据库:
books.map(function(book) {
// Insert into DB
});
每本书的外观如下:
var book = {
title: 'Book title',
author: 'Author name'
};
但是,在插入每本书之前,我需要从单独的表中检索作者的 ID,因为该数据已标准化。作者可能存在也可能不存在,所以我需要:
- 检查作者是否存在于数据库中
- 如果是,请使用此 ID
- 否则,插入作者并使用新ID
不过,上面的操作也都是异步的。
我可以在原始映射(获取和/或插入 ID)中使用承诺作为插入操作的先决条件。但这里的问题是,由于一切都是异步运行的,代码很可能会插入重复的作者,因为初始的 check-if-author-exists 与 insert-a-new-author 块是分离的。
我可以想到几种方法来实现上述目标,但它们都涉及拆分承诺链,而且通常看起来有点混乱。这似乎是必须经常出现的问题。我确定我在这里遗漏了一些基本的东西!
有什么建议吗?
【问题讨论】:
-
你不想要一个 "Upsert" 类型的方法。即总是会返回一个作者ID,如果它不存在那么它会创建它,如果它确实存在那么它只会返回现有的作者ID?这样一来,您就可以减少在检查插入之间插入某些东西的机会。您可能还想在这里使用某种锁定机制
-
你要插入多少本书,你的数组有多大?最好先返回一组所有作者 ID,然后在客户端合并该数据。此外,很多这种逻辑可能在数据库中执行得更好,而不是在 JavaScript 中。
-
对于这样做的正确方法是值得的,这将是一个 upsert 并让数据库为您处理这个问题。问题是 upsert 是非常新的(5 天前在 Pg 中实施)所以 knex 还没有赶上。
-
另外,如果可能的话,您真的想发送单个查询,而不是批处理
n插入。在客户端实现这种逻辑和并发管理对我来说似乎很愚蠢。使用事务可能会更简单。
标签: javascript node.js asynchronous promise bluebird