Interdependent Transactions with pg-promise

a 夏天 提交于 2019-12-01 20:59:39

The main problem you have - you can't use the root-level db object inside a task or transaction. Trying to create a new connection while inside a transaction breaks the transaction logic. You would need to use t.tx in such cases. However, in your case I don't see that you need it at all.

corrected code:

privateAPIRoutes.post('/ask', (req, res) => {
    console.log('/ask req.body: ', req.body);
    db.tx(t => {
        return t.one(
            `
        INSERT INTO
        posts (title, text, post_url, author_id, post_type)
        VALUES
        ($(title), $(text), $(post_url), $(author_id), $(post_type))
        RETURNING *
        `,
            {
                title: req.body.title,
                text: req.body.text,
                post_url: slug(req.body.title),
                author_id: req.user.id,
                post_type: 'question'
            } // remember req.user contains decoded jwt saved by mw above.
        )
            .then(post => {
                console.log('/ask second query: post[0]: ', post);
                console.log('/ask second query: tags: ', req.body.tags);
                console.log('/ask second query: tags[0]: ', req.body.tags[0]);

                // the key piece to the answer:
                var tagIds = req.body.tags.map(tag => {
                    return tag.id || t.one("insert into tags(tag) values($1) returning id", tag.label, a=>a.id);
                });

                return t.batch(tagIds)
                    .then(ids => {
                        var queries = ids.map(id => {
                            return t.one(
                                `
                                INSERT INTO post_tag (post_id, tag_id)
                                VALUES ($(post_id), $(tag_id))
                                RETURNING post_id, tag_id
                                `,
                                {
                                    post_id: post.id,
                                    tag_id: id
                                }
                            )
                        });
                        return t.batch(queries);
                    });
            });
    })
        .then(data => {
            // data = result from the last query;
            console.log('/api/ask', data);
            res.json(data);

        })
        .catch(error => {
            // error
        });
});

The key here is simply to iterate through the tag id-s, and for the ones that are not set - use an insert. Then you settle them all by passing the array into t.batch.


Other recommendations:

  • You should use method one when executing an insert that returns the new record columns.
  • You should use try/catch only once there, on the transaction. This is relevant to how to use promises, and not just for this library
  • You can place your queries into external SQL files, see Query Files

To understand conditional inserts better, see SELECT->INSERT

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!