Meteor中使用MongoDB $lookup聚合发布数据失败的问题排查
问题背景
现有两个MongoDB集合swapBuckets和locations,需要通过locationId字段将locations的数据关联聚合到swapBuckets中。集合数据结构如下:
// swapBuckets集合数据 { "_id" : "rcmiajXkYBDWdYmjL", "capacity" : "5 gallon", "color" : "white", "contentStatus" : "empty", "locationId" : "jNjewKekCmhwTgL9d", } // locations集合数据 { "_id" : "jNjewKekCmhwTgL9d", "name" : "Nourish Organic Juice", "number" : 1, }
使用tunguska:reactive-aggregate包在Meteor中实现聚合发布,服务器端代码:
import { ReactiveAggregate } from "meteor/tunguska:reactive-aggregate"; import { SwapBucketsCollection } from "/imports/api/SwapBuckets/collection"; if (Meteor.isServer) { Meteor.publish("swapBucketsLocation", function () { ReactiveAggregate( this, SwapBucketsCollection, [ { $lookup: { from: "locations", localField: "locationId", foreignField: "_id", as: "location", }, }, ], { clientCollection: "swapBucketsWithLocation" } ); }); }
客户端Vue.js 2组件代码:
<script> const SwapBucketsWithLocation = new Mongo.Collection('swapBucketsWithLocation'); export default { meteor: { $subscribe: { swapBucketsLocation: [] }, swapBuckets() { const swapBuckets = SwapBucketsWithLocation.find({}, { sort: { number: 1 } }).fetch(); if (swapBuckets) { return swapBuckets; } return []; }, }, }; </script>
出现的问题:Chrome的Meteor开发工具中SwapBucketsWithLocation集合已创建但无数据,服务器控制台报错:
I20220719-10:30:42.656(-6)? Exception from sub swapBucketsLocation id ACiiCuPna7WE72GB8 TypeError: Cannot convert undefined or null to object I20220719-10:30:42.657(-6)? at Function.entries (<anonymous>) I20220719-10:30:42.658(-6)? at ReactiveAggregate (packages/tunguska:reactive-aggregate/aggregate.js:56:37) I20220719-10:30:42.658(-6)? at Subscription._handler (imports/api/SwapBuckets/publications.js:10:5) I20220719-10:30:42.658(-6)? at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1885:12) I20220719-10:30:42.659(-6)? at packages/ddp-server/livedata_server.js:1107:9 I20220719-10:30:42.659(-6)? at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1257:12) I20220719-10:30:42.659(-6)? at Subscription._runHandler (packages/ddp-server/livedata_server.js:1106:60) I20220719-10:30:42.659(-6)? at Session._startSubscription (packages/ddp-server/livedata_server.js:917:9) I20220719-10:30:42.659(-6)? at Session.sub (packages/ddp-server/livedata_server.js:673:12) I20220719-10:30:42.660(-6)? at packages/ddp-server/livedata_server.js:603:43
问题原因及解决办法
1. 检查集合实例有效性
报错指向ReactiveAggregate函数中的Object.entries调用,大概率是传入的SwapBucketsCollection集合实例异常。需确认:
- 集合的导出路径正确,服务器端能正确导入
SwapBucketsCollection是通过Mongo.Collection正常创建的有效集合对象
2. 确认$lookup的from字段值
$lookup的from字段需要匹配MongoDB中集合的实际名称,而非Meteor中的集合变量名。如果创建locations集合时指定了自定义名称(如new Mongo.Collection('custom-locations')),需将from的值改为对应名称。
3. 完善发布函数的返回逻辑
在Meteor发布函数中,需明确告知客户端发布完成状态,可在ReactiveAggregate调用后添加this.ready():
if (Meteor.isServer) { Meteor.publish("swapBucketsLocation", function () { ReactiveAggregate( this, SwapBucketsCollection, [ { $lookup: { from: "locations", localField: "locationId", foreignField: "_id", as: "location", }, }, ], { clientCollection: "swapBucketsWithLocation" } ); // 通知客户端发布完成 return this.ready(); }); }
4. 检查包版本兼容性
tunguska:reactive-aggregate与当前Meteor版本不兼容可能导致类型错误,尝试更新包到最新稳定版:
meteor update tunguska:reactive-aggregate
5. 验证字段类型匹配
确保swapBuckets中的locationId和locations中的_id类型完全一致(均为字符串或均为ObjectId),类型不匹配会导致$lookup匹配失败,聚合结果为空。
内容的提问来源于stack exchange,提问作者Śāntanu

