Загрузка записей из дочерней таблицы с помощью API node.js - PullRequest
0 голосов
/ 12 марта 2019

Хорошо,

Я довольно новичок в node.js и в целом концепции функций обратного вызова, и я ломал голову, пытаясь понять это. Может быть, некоторые из вас, ребята, могут помочь.

Итак, основная настройка заключается в том, что у меня есть приложение React / Redux на внешнем интерфейсе, которое использует API в качестве источника данных. Спереди я хочу загрузить некоторое количество продуктов одновременно и загрузить все их изображения, затем у меня есть компонент Product, который показывает один продукт и отображает галерею изображений (поэтому мне нужны все изображения продуктов на один раз)

Я пытаюсь написать API, когда запрашиваю http://myapi.com/randomproducts/, который будет возвращать указанное количество случайных продуктов из базы данных MySQL. Эта часть у меня есть. Вот часть, которая бросает меня ... каждый продукт, который я возвращаю в этом массиве продуктов, имеет неизвестные изображения, связанные с ним. Я хочу загрузить их в одно и то же время, чтобы мои возвращаемые данные выглядели примерно так:

[
  {
    product_id: 0,
    product_name: "my cool product",
    product_desc: "desc of my cool product",
    price: 10.00,
    product_images: [
          {
            product_image_id: 10,
            product_image:  "img1.jpg",
          },
          {
            product_image_id: 11,
            product_image:  "img2.jpg",
          },
          {
            product_image_id: 12,
            product_image:  "img3.jpg",
          }
    ]
  },
  {
    product_id: 2,
    product_name: "my other cool product",
    product_desc: "desc of my other cool product",
    price: 20.00,
    product_images: [
          {
            product_image_id: 13,
            product_image:  "img21.jpg",
          },
          {
            product_image_id: 14,
            product_image:  "img22.jpg",
          },
          {
            product_image_id: 15,
            product_image:  "img23.jpg",
          }
    ]
  },

]

... и т. Д.

Таким образом, очевидно, что есть отношения родитель-потомок между products (родительская таблица) и product_images (дочерняя таблица). К сожалению, мне не удалось создать API-функцию, которая будет возвращать массив изображений, который также имеет массив связанных изображений. Конечная цель состоит в том, чтобы я хотел загружать сразу несколько продуктов и связанных с ними изображений за один вызов API, вместо того чтобы получать продукты, а затем получать изображения.

Вот снимок таблиц базы данных:

НАЖМИТЕ ЗДЕСЬ, ЧТОБЫ ПОСМОТРЕТЬ ТАБЛИЦЫ БАЗЫ ДАННЫХ

Вот код, который у меня есть:

1. МАРШРУТ

Отправьте текст / json body на этот маршрут. Он принимает идентификатор пользователя и количество возвращаемых продуктов:

app.route('/multiplerandomproducts/')
.post(products.get_multiple_random_products);

post body:  {user_id: <num>, product_count: <num>}

2. ПОЛУЧЕНИЕ МОИХ ПРОДУКТОВ

В моем контроллере ProductsController.js у меня есть следующее:

exports.get_multiple_random_products = function(req,res) {
  var postData = new Product(req.body);
  Product.getMultipleRandomProducts(postData.data, function(err,products) {
    if(err) {
      res.send(err); 
    } else {
      res.json(products);
    }
  });
}

В моей модели Products.js у меня есть следующее:

// get a random product for the userId
Product.getMultipleRandomProducts = function getMultipleRandomProducts(postData, result) {
    var userId = postData.user_id;
    var productCount = postData.product_count;

    var sqlStr = "SELECT DISTINCT a.* FROM product a "
    + " INNER JOIN product_category b ON b.product_id = a.product_id "
    + " INNER JOIN user_category c ON c.category_id = b.category_id "
    + " WHERE c.user_id= ? "

    // get only products that the user hasn"t seen before
    if(process.env.APP_HIDESEENPRODS === "1") {
        sqlStr += " AND a.product_id NOT IN (SELECT c.product_id from seen_product c WHERE c.user_id = ?)";
    }

    sqlStr += " ORDER BY RAND() LIMIT ?";

    sql.query(sqlStr, [userId, userId, productCount], function(err, res) {
        if(err) {
            result(err, null);
        } else {
            // hide from the use if this flag is set in the app
            if(!process.env.APP_HIDESEENPRODS === "1") {
                insertUserSeenProduct(userId, res[0].product_id);
            }
            result(null,res);
        }
    });
}

У меня также есть модель ProductImages.js, которая в качестве метода получения изображений для определенного продукта выглядит следующим образом:

ProductImage.getAllProductImages = function getAllProductImages(productId, result) {
        sql.query("Select * from product_image WHERE product_id = ? ", productId, function (err, res) {
                if(err) {
                    console.log("error: ", err);
                    result(null, err);
                }
                else {
                    result(null, res);
                }
            });   
    };

Что я пробовал:

Так что это версия моей функции, которую я пытался реализовать. Когда я указываю, что хочу три записи, я получаю объект с тремя нулевыми значениями, то есть [ноль, ноль, ноль]. Я думаю, что я близко, просто не вижу, что я делаю неправильно ....

Product.getMultipleRandomProducts = function getMultipleRandomProducts(postData, result) {
    var userId = postData.user_id;
    var productCount = postData.product_count;

    var sqlStr = "SELECT DISTINCT a.* FROM product a "
    + " INNER JOIN product_category b ON b.product_id = a.product_id "
    + " INNER JOIN user_category c ON c.category_id = b.category_id "
    + " WHERE c.user_id= ? "

    // get only products that the user hasn"t seen before
    if(process.env.APP_HIDESEENPRODS === "1") {
        sqlStr += " AND a.product_id NOT IN (SELECT c.product_id from seen_product c WHERE c.user_id = ?)";
    }

    sqlStr += " ORDER BY RAND() LIMIT ?";

    sql.query(sqlStr, [userId, userId, productCount], function(err, res) {
        if(err) {
            result(err, null);
        } else {
            // hide from the use if this flag is set in the app
            if(!process.env.APP_HIDESEENPRODS === "1") {
                insertUserSeenProduct(userId, res[0].product_id);
            }
            result(null, res.map((item) => {
                sql.query("Select * from product_image WHERE product_id = ? ", item.product_id, function (err, res2) {
                    if(err) {
                        console.log("error: ", err);
                        result(null, err);
                    }
                    else {
                        item.product_images = res2;
                    }
                });                  
            }));
        }

    });
}

Проблема, с которой я сталкиваюсь:

Итак, я попытался просто перебрать возвращенный массив продуктов, в который я вернулся, и получить изображения продуктов, которые работали бы хорошо, если бы это не было асинхронным. Но когда я пытаюсь это сделать, я возвращаю объект с тремя продуктами (если я запрашиваю три), но только одному (первому) из этих продуктов назначены изображения.

Итак, я хочу вернуть один объект, который выглядит примерно так:

  • Продукт
    • изображение
    • изображение
    • изображение
  • Продукт
  • изображение
  • изображение
Продукт
  • изображение
  • изображение
  • изображение

Итак, может кто-нибудь, пожалуйста, Скажите, пожалуйста, как я могу это сделать? Я все еще пытаюсь обернуться вокруг функций обратного вызова, и у меня скоро будет аневризма мозга!

Спасибо !!

1 Ответ

0 голосов
/ 12 марта 2019

Поскольку изображения каждого продукта выбирались индивидуально, ожидаемый результат - это то, что вы получаете сейчас.Фактически, если вы используете сервер (не локальный), скорее всего, изображения не вернутся ни к одному из продуктов.

Используйте async/await и promisify вашу функцию для получения производственных изображений:

sql.query(sqlStr, [userId, userId, productCount], async function(err, res) {
    if(err) {
        result(err, null);
    } else {
        // hide from the use if this flag is set in the app
        if(!process.env.APP_HIDESEENPRODS === "1") {
            insertUserSeenProduct(userId, res[0].product_id);
        }

        // Get the list of images thru promisify
        const getImages = function(item) {
            return new Promise( function(resolve, reject) {
                sql.query("Select * from product_image WHERE product_id = ? ", item.product_id, function (err, res2) {
                    if(err) {
                        console.log("error: ", err);
                        reject(result(null, err));
                    }
                    else {
                        item.product_images = res2;

                        resolve(item);
                    }
                });
            });
        };

        let products = [];

        const returnFalse = () => false;

        for (let i = 0; i < res.length; i++ ) {
            let product = await getImages(res[i]).catch(returnFalse);

            if (product) {
                products.push(product);
            }
        }

        result( null, products);
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...