У вас асинхронный код. Логично, что
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);
}));
});