Задать вопрос
@bagzon
Backend PHP, NodeJs, JS

Как связать две модели в одну посредством перебора в node.js and mongoos?

Есть две модели простые, связть один ко многим.
1 - product
2 - product_info (тут есть поле product_id)
Так вот, пытаюсь все это заджонить. Но у меня не получается, мне кажется что-то конечно не то, но проблема именно в том, что цикл forEach пробегает быстрее чем данные запушаться в итоговый массив. И в итоге def.resolve(result); пусто

var mongoose = require('mongoose');
var Q = require('q');

var catalog = function(app) {
    var product = mongoose.model('product', require('../model/product'));
    var productInfo = mongoose.model('product_info', require('../model/ProductInfo'));

    var getAllProducts = function() {
        var result = [];
        var def = Q.defer();

        product.find(function(err, products) {
            products.forEach(function(product) {
                productInfo.find({product_id: product._id}, function(err, info) {
                    product.info = info;
                    result.push(product);
                });
            });

            def.resolve(result);
        });

        return def.promise;
    };

    return {
        getAllProducts : getAllProducts
    };
};

module.exports = catalog;


и вот вызываем

var products = require('../src/catalog')(app).getAllProducts();

        products.then(function (products) {
            console.log(products);
            res.render('index', { products : products });
        });


Как все это сделать более грамотно? спасибо.
  • Вопрос задан
  • 523 просмотра
Подписаться 1 Оценить Комментировать
Решения вопроса 1
@iShatokhin
JS developer
У вас асинхронный код. Логично, что def.resolve(result) сработает раньше, чем закончится любой из productInfo.find.
Вам нужен контроль выполнения асинхронного кода, например async.

product.find(function(err, products) {
  async.each(products, function (product, cb) {
    productInfo.find({product_id: product._id}, function(err, info) {
      product.info = info;
      cb(err);
    });
  }, function (err) {
    def.resolve(products);
  });
});


Другой вариант вашего кода в один запрос и без async:

product.find(function(err, products) {
 var p_ids = products.map(function (product) { // создаем массив id продуктов
    return product._id; 
  });

  productInfo.find({product_id : {$in:  p_ids}}, function(err, infos) { // запрашиваем info для всех совпадающих id продуктов в массиве
    var obj = infos.reduce(function(a, b) { // создаем коллекцию для быстрого поиска, где ключ - id продукта
      return a[b.product_id ] = b;
    }, {});

    products.forEach(function (product) {
      product.info = obj[product._id];
    });

    def.resolve(products);
  }));
});
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы