Как достать результат запроса findOne через этот Promise в mongoose?

Я изучал и понял что результат команды find и findOne нельзя вернуть вне функции которая передаётся вторым аргументом в них.
Так вот можно вынуть только через Promise, я сделал вот такой код:

    var ret = Account.findOne({
    num: 256
    });
    ret.model['$init'].then(function(A) {
    	console.log(A); //выводит модель
    }, function() {
    	console.log('fail');
    });

Account это модель mongoose.
Так вот аргумент A выдаёт ту же самую модель, а другие аргументы промис не передаёт. Мне нужно вернуть найденный объект во внешнюю переменную чтоб с ним по нормальному работать

Асинхронные API (что на коллбеках что на промисах) так или иначе требуют от тебя объявить функцию, которая принимает данные для обработки (в твоем случае - объект пользователя) как аргумент. И этот коллбек передать асинхронному API.

Пример на коллбеках

function processUser(user) {
	console.log('processing user', user)
}

Account.findOne({
	num: 256
}, function (error, user) {
	if (error) {
		// handle error
		return
	}
	processUser(user)
});

И на промисах

function processUser(userPromise) {
	userPromise.then(function (user) {
		console.log('processing user', user)
	})
}

var userPromise = findOne({
	num: 256
})
processUser(userPromise)

Если решения не подходят чтобы организовать обработку кода как ты хочешь, покажи как выгляит код обработки. Возможно он вносит такие ожидания от кода, которые невозможно реализовать на js.

Вот например мне надо сделать какую-то проверку:

var exist;
function processUser(user) {
	console.log(Object.keys(user));
	// Странный вывод: [ '$__', 'isNew', 'errors', '_doc', '$init' ]
	// if(user.arr[0] === 1) //не выходит
	// 	exist = true;
	// else
	// 	exist = false;
}

Account.findOne({
	num: 256
}, function (error, user) {
	if (error) {
		// handle error
		return
	}
	processUser(user);
});

console.log(exist);

Вывод совсем не тот что мне нужен. Вывод user вовзращает:

 { _id: 5b0b9663f30151310de58a18,
   num: 256,
   arr: [ 1, 5, 4, 7, 9, 9, 0 ] }

То есть я не могу теперь нормально обратится к массиву в найденном документе и в документации про это не написано ничего

  1. Убедись что у тебя только 1 документ с полем num: 256 и что он есть в коллекции.

  2. Ты запускаешь именно тот код который показываешь в комментарии?

  3. Вывод user вовзращает:

    Не вижу в коде где выводится user. Соответственно вопрос - как ты получил значение документа пользователя которое в комментарии?

  4. Нельзя писать код так чтобы асинхронные функции манипулировали переменной в общей области видимости. Я про подход с var exist; По шкале от -5 до +5, где -5 - полный отстой решение, 0 - нейтральное решение и +5 - идеальное решение это решение на -3.5.

    Та, функция, которой нужно знать о результате проверки должна предоставить функцию-коллбек. Нужно делать как в примере ниже.

Вот так выглядит проверка того что у пользователя в массиве arr есть элемент "item" с последующим рендером результата в темплейт (expressjs).

// Проверка что у пользователя в массиве `arr` есть элемент `"item"`
function checkHasItem(num, callback) {
	Account.findOne({
		num: num
	}, function (error, user) {
		if (error) {
			callback(error)
			return
		}
		if (user) {
			callback(null, user.arr.indexOf('item') !== -1)
		} else {
			callback({message: 'No user with num ' + num})
		}
	});
}

// routes
app.get('/has-item', function (req, res) {
	checkHasItem(req.params.num, function (err, userHasItem) {
		if (err) {
			res.render('error', {
				error: err
			})
		} else {
			res.render('index', {
				userHasItem: userHasItem
			})
		}
	})
})
  1. Это естественно соблюдается
  2. Другого нету
  3. Я заккоментировал потому что тот код приводит к ошибке, возвращаемый объект вообще не имеет в себе нужного массива arr
  4. Код просто для примера, мне надо чтобы всё работало, а потом естественно я смогу справится и без переменных
  5. Вот я написал подобный код:
function myCheck(num, callback) {
	Account.findOne({
		num: +num
	}, function (err, user) {
		if (err) {
			callback(err);
			return;
		}
		console.log(user);
		if(user)
			callback(null, user.arr.indexOf(num));
		else
			callback('Число не найдено');
	});
}

router.get('/test/:num', function(req, res) {
	myCheck(req.params.num, function(err, number) {
		if(err)
			res.send(err);
		else
			res.send('Число найдено. Находится в массиве по счёту: '+(number+1));
	});
	console.log('continue'); //и как же здесь предотвратить выполнение дальнейшего кода
	// Здесь могут быть строки которые не должны вызыватся если число
	// есть в базе данных
});

Выводит он данный объект:

{ _id: 5b0b9663f30151310de58a18,
  num: 256,
  arr: [ 1, 5, 4, 7, 9, 9, 0, 256, 324, 884, -1, 1 ] }

Но прошлая проблема так и не исчезла, на этот раз выходит немного другая ошибка:
TypeError: Cannot read property ‘indexOf’ of undefined

Вторую проблему можно исправить цепочками вызовов, а вот первую никак.
И самое смешное то что console.log(Array.prototype.slice.call(user)); выдаёт пустой массив

1 лайк

А ты описал свойство arr как массив когда создавал Account schem-у?

Судя по console.log-у нужное свойство есть, возможно mongoose оборачивает документ в свои getter-ы, а их работу описывает то как описана schem-а.

Да это же ужасно почти все типы указывать, если у меня их там 500 то это вообще полная бредятина, нельзя просто по нормальному обратится к коллекции и работать с ней как в mongo.
Всё я сделал так

var accountSchema = mongoose.Schema({
  arr: [Array]
}, {
	collection: 'test'
});

и всё наконец заработало.
Всё помощь больше не нужна, теперь придётся постоянно ухищрятся и ещё работать с длинными цепочками чтоб сделать мой проект