我有一个要解析的对象数组。我检查Mongo以查看记录是否存在条目。如果是这样,我将更新记录。否则,我创建记录。一切正常。但是,在循环过程之后,我想执行mongoose.disconnect()。但是,这在循环期间发生。我以前做过,但是这次略有不同,我没有任何运气。唯一不同的是,我正在调用另一个在保存新条目时需要等待的函数。
mongoose.set('useCreateIndex', true);
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log('MongoDB Connected'))
.then(async () => {
await parseWIP(converted);
mongoose.disconnect();
})
.catch(err => console.log(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.log(`Updated WIP`);
});
} else {
// Create new record
await createNewWip(wip);
}
})
.catch(err => {
console.log(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.log(savedWipRecord._id);
})
.catch(err => reject(err));
resolve();
});
}
我已经尝试过forEach for(let wip of array)和for(let wip in array)。为什么诺言立即返回?
答案 0 :(得分:2)
如果您要在函数上调用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.log(`Existing WIP: ${existingWip.id}`);
... assign some values ...
existingWip.lastModified = moment.now();
await existingWip.save().then(updatedWip => {
console.log(`Updated WIP ${updatedWip.id}`);
});
} else {
// Create new record
await createNewWip(wip);
}
})
.catch(err => {
console.log(err);
reject(err);
});
}
console.log('here we are at end of loop');
resolve();
});
}
答案 1 :(得分:1)
为什么只用一种标准方式将async/await
与标准Promise语法混合使用呢?同样,所有猫鼬方法无论如何都返回一个Promise
,所以我不明白为什么您甚至有任何尝试用Promise
包装回调的东西。
清单基本上显示了对Promises和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.log(`Existing WIP: ${existingWip.id}`);
... assign some values ...
existingWip.lastModified = moment.now();
let updatedWip = await existingWip.save()
console.log(`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
(即本机猫鼬方法result),并确保您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.log(`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()
模式是真正的坏习惯,并且基本上引入了来回请求的额外开销,以及您读取的数据存在的明显问题您决定将其写回时,可能已被另一个进程/更新更改。