Получите дерево родителей и детей с помощью pg-prom

Я использую библиотеку pg-promise с bluebird для выполнения зависимых запросов. У меня есть две таблицы, a и b, которые выглядят так:

|   a   |     |   b   |  
|-------|     |-------|
| a_id  |     | b_id  |
| prop1 |     | prop2 |
              |  b_a  |

где b.b_a - ссылка на a.a_id. Я хочу выбрать все записи, соответствующие заданному prop1, и результат должен содержать все совпадающие a-строк плюс соответствующие b-строк для каждого a. Это должно быть выполнено с двумя зависимыми запросами. Оба запроса могут возвращать несколько результатов.

Если таблица a возвращает только одну строку, я могу сделать это:

function getResult(prop1) {
    return db.task(function (t) {
        return t.one("select * from a where prop1=$1", prop1)
            .then(function (a) {
                return t.batch([a, t.any("select * from b where b_a=$1", a.a_id)]);
            })
            .then(function (data) {
                var a = data[0];
                var bs = data[1];
                bs.forEach(function (b) {
                    b.a = a;
                });
                return bs;
            });
    });
}

И я также могу получить все совпадающие b-записи для нескольких a-результатов, например:

function getResult(prop1) {
    return db.task(function (t) {
        return t.many("select * from a where prop1=$1", prop1)
            .then(function (as) {
                var queries = [];
                as.forEach(function (a) {
                    queries.push(t.any("select * from b where b_a=$1", a.id));
                });
                return t.batch(queries); // could concat queries with as here, but there wouldn't be a reference which b row belongs to which a row
            })
            .then(function (data) {
                // data[n] contains all matching b rows
            });
    });
}

Но как объединить этих двоих?


person Krxldfx    schedule 06.06.2016    source источник
comment
Они в одном порядке, правда? Так что просто обращайтесь к as[n] вместе с data[n]. Посмотрите здесь, как получить доступ к as.   -  person Bergi    schedule 06.06.2016
comment
Спасибо за ссылку, это может помочь. Но между a и b существует связь один-ко-многим, поэтому индайсы здесь не помогут.   -  person Krxldfx    schedule 06.06.2016
comment
Какое возвращаемое значение batch? Разве data не какой-то двумерный массив?   -  person Bergi    schedule 06.06.2016
comment
Только что увидел, что это многомерно, за секунду до того, как я прочитал ваш комментарий .. Большое спасибо за это, мог бы видеть это раньше!   -  person Krxldfx    schedule 07.06.2016
comment
where a.a_b is a reference - в таблице a нет a_b.   -  person vitaly-t    schedule 07.06.2016
comment
the result should contain all matching a-rows plus the corresponding b-rows for each a. хотите ли вы один объект с деревом или какой-нибудь массив? Не совсем понятно, какой именно тип вывода вам нужен.   -  person vitaly-t    schedule 07.06.2016
comment
@Krxldfx Я опубликовал для вас ответ ниже;)   -  person vitaly-t    schedule 07.06.2016


Ответы (1)


Я являюсь автором pg-обещания.


Когда у вас есть 2 таблицы: Parent -> Child с отношением 1-ко-многим, и вы хотите получить массив совпадающих Parent строк, каждая строка расширяется с помощью свойства children, установленного на массив соответствующих строк из таблицы Child ...

Для этого есть несколько способов, например сочетание pg-обещания и обещаний в вообще очень гибкий. Вот самая короткая версия:

db.task(t => {
    return t.map('SELECT * FROM Parent WHERE prop1 = $1', [prop1], parent => {
        return t.any('SELECT * FROM Child WHERE parentId = $1', parent.id)
            .then(children => {
                parent.children = children;
                return parent;
            });
    }).then(t.batch) /* this is short for: data => t.batch(data) */
})
    .then(data => {
        /* data = the complete tree */
    });

Вот что мы там делаем:

Сначала мы запрашиваем Parent элементов, затем сопоставляем каждую строку с запросом для соответствующих Child элементов, который затем устанавливает свои строки в Parent и возвращает его. Затем мы используем метод batch для разрешения массива Child запросов. возвращается из метода map.


Задача разрешится с таким массивом:

[
    {
        "parent1-prop1", "parent1-prop2",
        "children": [
            {"child1-prop1", "child1-prop2"},
            {"child2-prop1", "child2-prop2"}
        ]
    },
    {
        "parent2-prop1", "parent2-prop2",
        "children": [
            {"child3-prop1", "child3-prop2"},
            {"child4-prop1", "child4-prop2"}
        ]
    }    
]

Ссылки на API: карта, партия

ОБНОВЛЕНИЕ

См. Лучший ответ на этот вопрос: JOIN table as array of результаты с PostgreSQL / NodeJS.

person vitaly-t    schedule 06.06.2016
comment
Большое спасибо, map здесь очень помог - я как-то сам этого не нашел. - person Krxldfx; 07.06.2016
comment
@Krxldfx map - это всего лишь удобный метод, который делает ваш код короче, но не является строго обязательным для реализации вашей задачи;) - person vitaly-t; 07.06.2016
comment
@Krxldfx Обновлено со ссылкой на лучший / более полный ответ;) - person vitaly-t; 04.02.2017