-3

введите сюда описание изображения

Первый раз пишу на node.js.Этот кусок кода делает то, что мне надо, за тем лишь исключением, что экспортируется пустой массив. Я так понимаю, что он не ждет результата обращения к базе, а сразу выполняет присваиваение module.exports. Как решить?

P.S. строчка return MainPageList разумеется лишняя.

diproart
  • 2,588
  • Эм.. Экспорт не бывает асинхронным, советую пересмотреть архитектуру. – Qwertiy Jun 09 '17 at 09:10
  • 5
    Добавте Ваш код в текстовом виде. – 0xdb Jun 09 '17 at 09:10
  • node.js асинхронный по своей природе -https://stackoverflow.com/questions/18883757/module-export-function-not-returning-results. – diproart Jun 09 '17 at 09:15
  • 1
    Можно експортировать функцию, которая установить соеденение с бд и вернет колбек с массивом. Так как у вас работать не будет, потому что екпорт идет на этапе компиляции, а не выполнения. – Nazar Kalytiuk Jun 09 '17 at 09:27
  • Что мне делать-то? Я хочу создать модуль, который подключу в другом месте и присвоением x = require('мой модуль') получить в x готовый массив. Я в принципе не могу так сделать? – Андрей Jun 09 '17 at 09:44

3 Answers3

2

node.js асинхронный по своей природе, поэтому нужно использовать архитектуру основанную на функциях обратного вызова или промисах (Promise).

Вариант 1 (Callback):

// ...
module.exports = (opts, callback) => {
   User.find(opts.query, (err, result) => {
     if(err) throw new Error(err)
     // or if (err) return callback(err, null)
     callback(null, result)
   })
}

получить данные

const users = require('./users')

// параметры запроса
let opts = {query: { name: 'Name'}} 

// получение данных
users(opts, (err, result) => {
   if (err) throw new Error(err)
   // ответ, данные 
   console.log(result)
})

Вариант 2 (Promise): Mongoose возвращает Promise по умолчанию см. http://mongoosejs.com/docs/promises.html

// ...
module.exports = (opts) => {
   return Users.findOne(opts.query)
}

получить данные

const users = require('./users')
users({query: {name: "Name"}})
  .then(results => console.log(results))
  .catch(err => console.log(err))

Промисы более современный и более удобный подход для работы в асинхронном контексте. Промисы можно объединять в цепочки, тем самым избегать так называемого "callback hell", когда функции обратного вызова приходится вкладывать одна в другую, для ожидания результата. Также для работы с асинхронными потоками в node.js, можно использовать отличный модуль async

Еще простой пример на основе кода вопроса:

// ... настройка подключения пропущена, для краткости
module.exports = function(callback){
   // указываем, что выбирать только поле 'name'
   // @see http://mongoosejs.com/docs/api.html#model_Model.find
   User.find({}, 'name -_id', function(err, result) {
      if (err) throw new Error(err);
      // проверки isArray, .length и т.д. пропущены...
      // преобразование в простой массив с "именами"
      var users = result.map(function(item){ return item.name; });
      callback(users);
   });
};

Получаем данные, где-то в другом модуле

var users = require('./users');
users(function(result){
  // далее логика обработки полученных данных...
  console.log(result);
});

Ссылки:

diproart
  • 2,588
  • Ничего не понял. Мы экспортируем функцию с коллбеком. А когда получаем данные, то делаем этот с помощью промисов что ли? – Андрей Jun 09 '17 at 10:36
  • Это разные варианты, ответ обновил. – diproart Jun 09 '17 at 10:55
  • Я совсем тупенький,, обнови еще раз. Мне не нужны здесь опции запроса к базе, мне нужно, чтобы на выходе получался массив не из юзеров, а из имен юзеров- т.е. то, что я делал через forEach. – Андрей Jun 09 '17 at 11:16
  • Добавлен ещё пример. Mongoose может получать только нужные поля. – diproart Jun 09 '17 at 11:48
  • Если так, то на выходе я получаю массив состоящий из объектов, объекты состоят из полей id и name. А нельзя ли быстро и просто получить на выходе массив состоящий из значений полей name? – Андрей Jun 09 '17 at 12:28
  • Это можно сделать разными способами, .map, .forEach. Важно обратить внимание на возможности mongoose при фильтрации элементов (в документации). Ответ обновлен. – diproart Jun 09 '17 at 12:59
  • То, как я получал из базы нужные мне данные- это мрак и ужас, иди сойдет для сельской местности?(тут мы опустим историю с экспортом) – Андрей Jun 09 '17 at 14:08
  • То ли я совсем тупой, то ли у меня уже мозг закипает. Я беру последний пример из вашего ответа. Пробую. Не работает. После экспорта console.log(result) возвращает undefined, а если вставить console.log(users) перед вызовом коллбека в самом модуле, то возвращает пустой массив. – Андрей Jun 09 '17 at 14:22
  • Да нет всё нормально, по началу трудно привыкнуть к логике node.js, если нет опыта работы с асинхронными функциями. вот код который работает https://jsbin.com/dogayitofu/edit?js (конечно не в браузере))), это для примера). Если "ваши массивы" пустые, возможно в них реально нет данных. – diproart Jun 09 '17 at 15:02
  • И ещё, тут уже "наразместили" однотипные примеры, я же обращаю внимание на саму логику работы node.js. То, что асинхронная природа node.js требует определенного подхода. Плюс есть соглашения по определению функций обратного вызова и ошибок и т.п. – diproart Jun 09 '17 at 15:13
1

Вот вам простой рабочий пример по вашему коду. Найдеюсь подойдет

файл export.js

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/users');

const userShema = mongoose.Schema({
    name: String,
    age: String,
    disciplines: String,
});

let User = mongoose.model('User', userShema);

// User.create({name: 'name1', age: '11', disciplines: 'ds'});

module.exports = (cb) => {
    User.find({}, (err, docs) => {
        let users = docs.map((c) => c.name);
        cb(users);
    });
};

файл app.js

const exp = require('./export');

exp((users) => {
    console.log(users);
});
-1

Присвоение module.exports = MainPageList выполняется до того как получается результат из User.find()

Ваш код будет работать если экспортировать функцию.

Файл so.js:

const mongoose = require('mongoose');

module.exports = function (callback) {
    mongoose.connect('mongodb://localhost/usersl');
    const userSchema = mongoose.Schema({
        name: String,
        age: String,
        disciplines: String
    });
    const User = mongoose.model('User', userSchema);
    User.find({}, (err, base) => {
        console.log(err);
        console.log(base);
        mongoose.connection.close();
        return callback(err, base);
    });
};

Вызов в функции из другого модуля:

const so = require('./so');

so((err, result) => {
  if (err) {
    return err;
  }
  const MainPageList = result.map((item) => item['name']);
  console.log(MainPageList);
});
Dmitry Taipov
  • 164
  • 1
  • 5