You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合关联Supplier后求和异常:匹配条件失效排查

问题分析与解决

问题背景

拥有Transaction和Supplier两个MongoDB集合,想要聚合指定国家境内外的交易总金额,以此对比进口与国内采购情况,但关联Supplier集合后匹配条件失效,返回的是所有交易的总金额。

原聚合代码:

let aggs = [
        {
            $match : { type : "out" },
        },
        {
            $lookup: {
                from:"suppliers",
                let: { country : "$location.country" },
                localField:"supplier",
                foreignField:"_id",
                as:"suppliers",
                pipeline: [
                    {
                        $match: {
                            $expr: {
                                $eq: [ '$suppliers.location.country', "United Kingdom" ]
                            }
                        },
                    },
                ]
            }
        },
        {
            $group: {
                _id: null,
                total: { $sum : { $divide: ['$price', 100] } }
            },
        }
    ];

Transaction Schema:

const TransactionSchema = mongoose.Schema({
    item: {type: String, required: true },
    category: {type: String },
    type: { type: String, enum: ['in', 'out'] },
    price: { type: Number, required: true, get: getPrice, set: setPrice },
    description: { type: String },
    supplier: {
        type: mongoose.SchemaTypes.ObjectId,
        ref: "Supplier"
    },
    customer: {
        type: mongoose.SchemaTypes.ObjectId,
        ref: "Customer"
    },
    project: { type: String },
    invoice_ref: { type: String },
    payment_method: { type: String },
    parent_transaction: {
        type: mongoose.SchemaTypes.ObjectId,
        ref: "Transaction"
    },
    date: { type: Date },
    createdAt: { type: Date, default: Date.now(), immutable: true },
    updatedAt: { type: Date, default: Date.now() }
});

Supplier Schema:

const SupplierSchema = mongoose.Schema({
    name: {
        type: String, unique: true
    },
    description: { type: String },
    website: { type: String },
    email: { type: String },
    location: {
        address: { type: String },
        town: { type: String },
        county: { type: String },
        postcode: { type: String },
        country: { type: String }
    }
});

错误原因

  1. $lookup子管道匹配路径错误:在lookup的子管道中,当前处理的是suppliers集合的单条文档,所以应该用$location.country而非$suppliers.location.country——$suppliers是你定义的输出数组名,子管道上下文里不存在这个字段。
  2. 多余且无效的let定义:你定义了let: { country : "$location.country" },但Transaction集合根本没有location字段(该字段属于Supplier),这个定义完全没用,还会造成逻辑混淆。
  3. 未过滤无匹配供应商的交易:即使lookup没有找到符合条件的供应商,原Transaction文档仍会被保留,只是suppliers数组为空,这些不符合条件的交易也会被计入总和,必须过滤掉这类文档。

修正后的代码

仅统计UK供应商交易总额

let aggs = [
    { $match : { type : "out" } },
    {
        $lookup: {
            from:"suppliers",
            localField:"supplier",
            foreignField:"_id",
            as:"suppliers",
            pipeline: [
                { $match: { "location.country": "United Kingdom" } }
            ]
        }
    },
    // 过滤掉未匹配到符合条件供应商的交易
    { $match: { suppliers: { $ne: [] } } },
    {
        $group: {
            _id: null,
            total: { $sum : { $divide: ['$price', 100] } }
        }
    }
];

同时统计境内(UK)与境外(非UK)交易总额

如果需要一次性对比两类交易的总额,可以用以下逻辑:

let aggs = [
    { $match : { type : "out" } },
    {
        $lookup: {
            from:"suppliers",
            localField:"supplier",
            foreignField:"_id",
            as:"supplierInfo"
        }
    },
    // 展开供应商信息(lookup返回数组,需转为单个对象)
    { $unwind: "$supplierInfo" },
    // 根据供应商国家分组统计
    {
        $group: {
            _id: {
                isUK: { $eq: ["$supplierInfo.location.country", "United Kingdom"] }
            },
            total: { $sum : { $divide: ['$price', 100] } }
        }
    },
    // 重命名字段让结果更直观
    {
        $project: {
            _id: 0,
            type: { $cond: ["$_id.isUK", "国内采购(UK)", "进口采购(非UK)"] },
            total: 1
        }
    }
];

内容的提问来源于stack exchange,提问作者Ashley Finlayson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:17:03