交易内的猫鼬findOne():未捕获的TypeError:无法读取未定义的属性'$ elemMatch'

时间:2019-01-08 15:23:40

标签: mongodb mongoose transactions

我已经花了很多时间了,我找不到解决办法。

我正在使用Node / Express,并尝试运行带有交易的Mongoose (^5.2.0) findOne 。对于数据库,我使用 run-rs 在内存中运行它。

该集合之前已填充有效文档,我可以使用 mongo shell 找到该文档:

rs:PRIMARY> db.lots.findOne("aaaabbbbccccdddd11112222")
{
    "_id" : ObjectId("aaaabbbbccccdddd11112222"),
    "availableQty" : 0,
    "expirationDate" : ISODate("2019-01-10T15:10:29.455Z"),
    "__v" : 0
}

但是,每当我在下面运行此代码时,都会出现错误:

const save = async (lotId) => {
    const session = await mongoose.startSession()
    await session.startTransaction()
    try {        
        let lot = await Lots.findOne(lotId, session)
        console.log('result: ' + lot)

        await session.commitTransaction()
        await session.endSession()
        return lot    
    } catch(err) {
        console.error('caught error: ' + err)
        await session.abortTransaction()
        await session.endSession()
        throw err
    }
}

错误:

Uncaught TypeError: Cannot read property '$elemMatch' of undefined
      at model.Query._castFields (node_modules/mongoose/lib/query.js:3873:22)
      at model.Query.Query._findOne (node_modules/mongoose/lib/query.js:1861:23)
      at process.nextTick (node_modules/kareem/index.js:333:33)
      at _combinedTickCallback (internal/process/next_tick.js:95:7)
      at process._tickCallback (internal/process/next_tick.js:161:9)

由于我的console.log从未被打印过,因此似乎甚至没有被catch()捕获。

1 个答案:

答案 0 :(得分:0)

尝试更改

findOne(lotId, session)

findById(lotId).session(session)

Mongoose使用Node.js MongoDB驱动程序,该驱动程序的语法与本机MongoDB略有不同。方法findOne接受不是id的对象(请参见https://mongoosejs.com/docs/api.html#model_Model.findOne)。所以您可以使用

findOne({ _id: lotId })

或者简单地

findById(lotId)

这两个方法都返回带有方法session的Query对象,该对象接受会话(请参见https://mongoosejs.com/docs/api.html#query_Query-session)。

我建议您先阅读有关交易的文档以阐明其他内容:https://mongoosejs.com/docs/transactions.html

编辑: 另外,要将await与Mongoose一起使用,您还需要在查询结束时使用exec(),因为Query对象不返回Promise而是仅返回thenable(请参阅https://mongoosejs.com/docs/promises.html)。

因此正确的查询应如下所示

const lot = await Lots.findById(lotId).session(session).exec();

希望有帮助, 托马斯:)