У меня есть массив объектов, которые я анализирую. Я проверяю Mongo, чтобы увидеть, существует ли запись для записи. Если да, то обновлю запись. в противном случае я создаю запись. Это работает нормально. Однако после обработки цикла я хочу выполнить mongoose.disconnect(). Однако это происходит во время цикла. Я делал это раньше, но на этот раз немного по-другому, и мне не повезло. Единственное, что отличается, это то, что я вызываю другую функцию, которая требует ожидания при сохранении новых записей.
mongoose.set('useCreateIndex', true);
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.info('MongoDB Connected'))
.then(async () => {
await parseWIP(converted);
mongoose.disconnect();
})
.catch(err => console.info(err));
});
function parseWIP(array) {
return new Promise(async (resolve, reject) => {
for (let wip of array) {
WIP.findOne({ query_here })
.then(async existingWip => {
if (existingWip && existingWip.id) {
// Update existing record
const salesOrderState = getPatientReadableStatus(
wip.work_in_progress_wip_state
);
existingWip.salesOrder.state = salesOrderState.state;
existingWip.salesOrder.info = salesOrderState.info;
existingWip.salesOrder.progress = salesOrderState.progress;
existingWip.lastModified = moment.now();
await existingWip.save().then(updatedWip => {
console.info(`Updated WIP`);
});
} else {
// Create new record
await createNewWip(wip);
}
})
.catch(err => {
console.info(err);
reject(err);
});
}
resolve();
});
}
function createNewWip(wip) {
return new Promise(async (resolve, reject) => {
let patientPhone = wip.patient_phone;
if (!wip.patient_phone && wip.patient_mobile) {
patientPhone = wip.patient_mobile;
}
const branch = await getBranchContactInfo(wip.sales_order_branch_office);
const salesOrderState = getPatientReadableStatus(
wip.work_in_progress_wip_state
);
let wipRecord = { ... objects ... };
const entry = new WIP(wipRecord);
await entry
.save()
.then(savedWipRecord => {
console.info(savedWipRecord._id);
})
.catch(err => reject(err));
resolve();
});
}
Я пробовал forEach для (пусть стирает массив) и для (пусть стирает в массиве). Почему обещание возвращается немедленно?
Я пробовал это изначально, и он сразу отключается. mongoose .connect(db, {useNewUrlParser: true}) .then(() => console.info('MongoDB Connected')) .then(() => {parseWIP(converted); }) .then(() = > mongoose.disconnect()) .catch(ошибка => console.info(ошибка));
Посмотрите мой ответ, хотя иметь и then, и await неудобно, проблема в том, что вы не используете возврат ожидаемого Promise
Используйте Promise.all вместо for (let wip of array). Цикл for откладывает связанный метод findOne и разрешается после запуска этих методов.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если вы хотите вызвать await для функции, сама функция должна вернуть Promise, в противном случае она обязательно вернётся немедленно, поскольку ничто не сообщает системе, какую часть вашего кода ждать.
Итак, решение будет примерно таким (не проверено, но идея должна быть довольно простой)
function parseWIP(array) {
return new Promise(async (resolve, reject) => {
for (let wip of array) {
//array.forEach(async wip => {
//let wip = array[key];
await WIP.findOne({ query_goes_here })
.then(async existingWip => {
if (existingWip && existingWip.id) {
// Update existing record
console.info(`Existing WIP: ${existingWip.id}`);
... assign some values ...
existingWip.lastModified = moment.now();
await existingWip.save().then(updatedWip => {
console.info(`Updated WIP ${updatedWip.id}`);
});
} else {
// Create new record
await createNewWip(wip);
}
})
.catch(err => {
console.info(err);
reject(err);
});
}
console.info('here we are at end of loop');
resolve();
});
}
Вы отключаетесь сразу после await parseWIP(data);?
Если вы пытались вернуть промис в функцию, а он все равно немедленно возвращается, это означает, что что-то внутри функции не ожидается должным образом.
Я думаю, вы забыли дождаться операции WIP.findOne.
Зачем смешивать async/await со стандартным синтаксисом Promise, если можно просто написать все одним стандартным способом. Кроме того, все методы мангуста в любом случае возвращают Promise, поэтому я не понимаю, почему вы даже пытаетесь обернуть обратный вызов Promise.
Листинг в основном показывает неправильное понимание промисов и async/await, поэтому пример здесь должен прояснить некоторые вещи:
// Require mongoose and add your model definitions
const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true };
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// get your 'data' from somewhere of course.
for ( let wip of data ) {
let existingWIP = await WIP.findOne(query_goes_here);
if (existingWip) { // Asking for "id" on null would be an error
// Update existing record
console.info(`Existing WIP: ${existingWip.id}`);
... assign some values ...
existingWip.lastModified = moment.now();
let updatedWip = await existingWip.save()
console.info(`Updated WIP ${updatedWip.id}`); // though you should understand this does not change
// as id is immutable
} else {
let newWip = await WIP.create(wip); // not sure why you are creating a function
// but all mongoose methods return a promise anyway
// maybe do something
}
}
} catch (e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Обратите внимание, что await в основном означает, что вам не нужно делать then(), потому что на самом деле это одно и то же, но только с более чистый синтаксис. То же самое относится и к .catch(), так как try..catch снова намного чище.
Разбейте это функционально, если необходимо, но если вы просто делаете быстрый скрипт для загрузки и обновления некоторых вещей, то, вероятно, в этом нет особого смысла. Просто убедитесь, что все реализации function() возвращают Promise (то есть результат собственного метода мангуста) и что вы await их.
Кроме того, вы можете в основном взглянуть на findOneAndUpdate() и, в частности, на опцию «upsert». Одно это в основном удалит ваше условие if..then..else и сделает все это в одном запросе вместо отдельных find() и save()
// Require mongoose and add your model definitions
const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true };
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// get your 'data' from somewhere of course.
for ( let wip of data ) {
let updatedWip = await WIP.findOneAndUpdate(
query_goes_here,
update_statement_goes_here,
{ upsert: true, new: true } // need these options
);
console.info(`Updated WIP ${updatedWip.id}`);
}
} catch (e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Или, конечно, если вам просто не нужно ничего делать в «цикле», вы можете просто использовать bulkWrite():
// Require mongoose and add your model definitions
const uri = 'mongodb://localhost:27017/test';
const opts = { useNewUrlParser: true };
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// get your 'data' from somewhere of course.
let result = await WIP.bulkWrite(
data.map(wip =>
({
updateOne: {
filter: query_based_on_wip_values
update: update_based_on_wip_values,
upsert: true
}
})
)
);
} catch (e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
И это, конечно, требует только запроса один к серверу с ответом один для всего содержимого в массиве. Если массив особенно велик, вы можете разбить его. Но опять же, для «большого массива» вы должны загружать данные по частям, чтобы не все они были в массиве.
В целом, выберите один структурный шаблон и придерживайтесь его, а также найдите время, чтобы понять методы API и то, что они делают. Обычно find() затем модифицируется в коде, а шаблон save() имеет вид действительно плохая практика и в основном вводит дополнительные накладные расходы на запросы туда и обратно, а также очевидную проблему, заключающуюся в том, что данные, которые вы читаете, могут быть изменены другим процессом/обновлением к тому времени, когда вы решите записать их обратно.
Почему async + await внутри
then? Это все Обещания....then(() => parseWIP(data)).then(() => mongoose.disconnect()).catch...