使用Mongoose watch函数触发类型错误:listener参数需为函数
Mongoose监听集合更新时aggregate导致的Listener参数错误问题
问题描述
我尝试用Mongoose的watch函数实现clients集合更新时同步更新users集合的部分字段,在Schema文件中写了以下代码:
// ... 省略部分Schema代码 const clientsCollection = mongoose.model('Client', clientSchema); clientsCollection.watch<Client>([], { fullDocument: 'updateLookup' }).on('change', updateUser); async function updateUser(data: ChangeStreamDocument<Client>) { //... 省略无关代码 const result = await clientsCollection.aggregate([ { $match: { userId: new ObjectId('abc123') } }, { $group: { _id: null, totalSaleValue: { $sum: '$clientSalesValue' } } }, { $unset: ['_id'] } ]).exec(); //... 后续更新users集合的代码 }
保存文件后立即触发Node.js错误:
TypeError [ERR_INVALID_ARG_TYPE]: The "listener" argument must be of type function. Received undefined
排查后发现注释aggregate代码段错误就消失,确认传入on的updateUser是有效函数,添加返回值也无法解决问题,请问问题出在哪里?
问题原因及解决方法
1. 函数定义顺序问题(核心原因)
虽然函数声明会被提升,但如果updateUser函数内部存在未捕获的初始化错误(比如未导入依赖类型),会导致函数在绑定到watch的change事件时未被正确初始化,最终传入undefined作为listener。
解决:
将updateUser函数的定义移到clientsCollection.watch().on()语句之前,确保绑定事件时函数已完全定义:
async function updateUser(data: ChangeStreamDocument<Client>) { //... 函数内容不变 } const clientsCollection = mongoose.model('Client', clientSchema); clientsCollection.watch<Client>([], { fullDocument: 'updateLookup' }).on('change', updateUser);
2. 检查依赖是否正确导入
确保你已经导入了代码中使用到的Mongoose类型和工具:
// ES Module写法 import mongoose, { ObjectId, ChangeStreamDocument } from 'mongoose'; // CommonJS写法 const mongoose = require('mongoose'); const { ObjectId, ChangeStreamDocument } = mongoose;
如果ObjectId未导入,new ObjectId('abc123')会触发引用错误,间接导致updateUser函数无法正常初始化。
3. MongoDB版本兼容问题
如果你的MongoDB版本低于4.2,$unset不支持数组格式,需要改为字符串格式:
{ $unset: '_id' // 替换为字符串而非数组 }
4. aggregate结果处理
aggregate().exec()返回的是数组,后续更新users集合时需要正确取值:
const totalSaleValue = result.length > 0 ? result[0].totalSaleValue : 0; // 用totalSaleValue更新users集合
内容的提问来源于stack exchange,提问作者GhostOrder
相关产品推荐
相关产品推荐

