更新
在提出一些建议后,我将代码修改如下:
const session = await mongoose.startSession()
session.startTransaction()
try {
const udpated = await Schema1.findByIdAndUpdate(
'id', { $set: { /* ... */ } }, { session }
)
const array = await Promise.all(
updated.array.map(async item => {
// change 1
const doc = await Schema2.findById(item.someId).session(session)
const payload = { /* ... */ }
// change 2
return new Schema3(payload).save({ session })
})
)
await session.commitTransaction()
session.endSession()
} catch (err) {
await session.abortTransaction()
session.endSession()
throw err
}
但这给了我另一个错误:
{
MongoError: internal atlas error checking things: Failure getting dbStats: read tcp 192.168.254.116:52242->192.168.254.116:27000: i/o timeout
at /some-path/node_modules/mongodb-core/lib/connection/pool.js:581:63
at authenticateStragglers (/some-path/node_modules/mongodb-core/lib/connection/pool.js:504:16)
at Connection.messageHandler (/some-path/node_modules/mongodb-core/lib/connection/pool.js:540:5)
at emitMessageHandler (/some-path/node_modules/mongodb-core/lib/connection/connection.js:310:10)
at TLSSocket.<anonymous> (/some-path/node_modules/mongodb-core/lib/connection/connection.js:453:17)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at TLSSocket.Readable.push (_stream_readable.js:208:10)
at TLSWrap.onread (net.js:597:20)
ok: 0,
errmsg: 'internal atlas error checking things: Failure getting dbStats: read tcp 192.168.254.116:52242->192.168.254.116:27000: i/o timeout',
code: 8000,
codeName: 'AtlasError',
name: 'MongoError',
[Symbol(mongoErrorContextSymbol)]: {} }
× Unexpected error occured MongoError: internal atlas error checking things: Failure getting dbStats: read tcp 192.168.254.116:52242->192.168.254.116:27000: i/o timeout
at /some-path/node_modules/mongodb-core/lib/connection/pool.js:581:63
at authenticateStragglers (/some-path/node_modules/mongodb-core/lib/connection/pool.js:504:16)
at Connection.messageHandler (/some-path/node_modules/mongodb-core/lib/connection/pool.js:540:5)
at emitMessageHandler (/some-path/node_modules/mongodb-core/lib/connection/connection.js:310:10)
at TLSSocket.<anonymous> (/some-path/node_modules/mongodb-core/lib/connection/connection.js:453:17)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at TLSSocket.Readable.push (_stream_readable.js:208:10)
at TLSWrap.onread (net.js:597:20)
顺便说一句:我也无需使用mongoose
重构了该代码(我只是将标准mongodb
客户端用于nodejs
,但仍然遇到这些错误。
由于this question中提到的问题,我正在使用mongoose
个交易。
但是,我的问题是,Promise.all()
的实现似乎不适用于mongoose
事务。问题可能来自将多个Schemas
与一个session
一起使用或创建了一组文档。 (但我真的不确定)
const session = await mongoose.startSession()
session.startTransaction()
try {
const udpated = await Schema1.findByIdAndUpdate(
'id', { $set: { /* ... */ } }, { session }
)
const array = await Promise.all(
updated.array.map(async item => {
const doc = await Schema2.findById(item.someId)
const payload = { /* ... */ }
return Schema3.createa(payload, { session })
})
)
await session.commitTransaction()
session.endSession()
} catch (err) {
await session.abortTransaction()
session.endSession()
throw err
}
我遇到错误,Schema3
的验证未能通过某些必需的路径。即使在console.log上找到payload
时也是如此。
{ ValidationError: xxx validation failed: xxx: Path `xxx` is required., xxx: Path `xxx` is required., xxx: Path `xxx` is required.
at ValidationError.inspect (/xxx/node_modules/mongoose/lib/error/validation.js:59:24)
at formatValue (util.js:400:38)
at inspect (util.js:294:10)
at format (util.js:223:18)
at Console.log (console.js:130:21)
at module.exports (xxx.js:228:17)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
errors:
{ xxx:
{ ValidatorError: Path `xxx` is required.
at new ValidatorError (/xxx/node_modules/mongoose/lib/error/validator.js:29:11)
at validate (/xxx/node_modules/mongoose/lib/schematype.js:871:13)
at /xxx/node_modules/mongoose/lib/schematype.js:924:11
at Array.forEach (<anonymous>)
at SchemaString.SchemaType.doValidate (/xxx/node_modules/mongoose/lib/schematype.js:880:19)
at /xxx/node_modules/mongoose/lib/document.js:1913:9
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
message: 'Path `xxx` is required.',
name: 'ValidatorError',
properties: [Object],
kind: 'required',
path: 'xxx',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true },
xxx:
{ ValidatorError: Path `xxx` is required.
at new ValidatorError (/xxx/node_modules/mongoose/lib/error/validator.js:29:11)
at validate (/xxx/node_modules/mongoose/lib/schematype.js:871:13)
at /xxx/node_modules/mongoose/lib/schematype.js:924:11
at Array.forEach (<anonymous>)
at ObjectId.SchemaType.doValidate (/xxx/node_modules/mongoose/lib/schematype.js:880:19)
at /xxx/node_modules/mongoose/lib/document.js:1913:9
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
message: 'Path `xxx` is required.',
name: 'ValidatorError',
properties: [Object],
kind: 'required',
path: 'xxx',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true },
xxx:
{ ValidatorError: Path `xxx` is required.
at new ValidatorError (/xxx/node_modules/mongoose/lib/error/validator.js:29:11)
at validate (/xxx/node_modules/mongoose/lib/schematype.js:871:13)
at /xxx/node_modules/mongoose/lib/schematype.js:924:11
at Array.forEach (<anonymous>)
at ObjectId.SchemaType.doValidate (/xxx/node_modules/mongoose/lib/schematype.js:880:19)
at /xxx/node_modules/mongoose/lib/document.js:1913:9
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickDomainCallback (internal/process/next_tick.js:218:9)
message: 'Path `xxx` is required.',
name: 'ValidatorError',
properties: [Object],
kind: 'required',
path: 'xxx',
value: undefined,
reason: undefined,
[Symbol(mongoose:validatorError)]: true } },
_message: 'xxx validation failed',
name: 'ValidationError' }
在不使用mongoose
事务的情况下重构代码时,一切正常:
try {
const udpated = await Schema1.findByIdAndUpdate(
'id', { $set: { /* ... */ } }
)
const array = await Promise.all(
updated.array.map(async item => {
const doc = await Schema2.findById(item.someId)
const payload = { /* ... */ }
return Schema3.createa(payload)
})
)
} catch (err) {
throw err
}
答案 0 :(得分:4)
我联系了MongoDB支持,结果发现这是一个已知问题:
我们当前了解到M0免费套餐集群存在问题,从而使多语句事务超时并出错。应该在推出MongoDB 4.0.5版时解决此问题。同时,如果您紧急需要此功能,建议您将群集升级到M10 +群集。
因此出现问题是因为我正在使用免费套餐。但是希望该错误将在MongoDB 4.0.5版本中修复。
更新
由于我的数据库现在在4.0.5版上运行,此问题已解决。因此,代码不一定有问题。
答案 1 :(得分:3)
尝试将.session(session)
添加到每个查询
const doc = await Schema2.findById(item.someId).session(session)
答案 2 :(得分:0)
好像您在findOne()
中缺少会话选项:
const doc = await Schema2.findById(item.someId, null, { session })
请参阅:https://mongoosejs.com/docs/api.html#model_Model.findOne
答案 3 :(得分:0)
我有一个类似的问题,我在一个会话中创建了一个文档,然后使用了从其他文档“ B”创建的._id,然后找到了具有其他属性的第一个文档,当第一个文档被推送时B在第一个文档中,我尝试的解决方案使用了多个session.startTransaction();
示例:
session.startTransaction();
创建第一个文档
await session.commitTransaction();
session.startTransaction();
创建第二个文档,使用其他属性搜索第一个文档 创建它的方式,然后将此B._id推送到第一个文档中,然后更新此第一个文档
await session.commitTransaction();
最后session.endSession()
当我再次搜索console.log(第一个文档)并将b推入它们时,我意识到了这一点,我想这就像在集群中提交一样?所以也许可以和其他会议一起使用...而且有效