【问题标题】:How to write a $match on a $lookup document in MongoDB如何在 MongoDB 中的 $lookup 文档上编写 $match
【发布时间】:2020-05-30 17:32:26
【问题描述】:

我有两个如下所示的 MongoDB 集合:

Products      Specials
----------    ----------
_id           _id
name          product_id
country       zip
price         percent_discount
              out_of_stock

我也在使用 GraphQL,所以我编写了一个聚合管道,以这种结构返回数据:

specials {
  _id
  product {
    _id
    name
    country
    price
  }
  zip
  percent_discount
  out_of_stock
}

我写的这个聚合管道效果很好,看起来像这样:

let response = await Specials.aggregate([
    {
        $lookup: {
            from: 'products',
            localField: 'product_id',
            foreignField: '_id',
            as: 'product'
        }
    },
    {
        $unwind: '$product'
    },
    {
        $match: {
            zip: zip
        }
    }
])

return response;

现在我正在尝试在其中添加一个过滤器。过滤器应与产品集合中的名称或国家/地区匹配,最好使用正则表达式。所以我试着写这样的东西,但它产生了超过 8000 个结果,而应该只有 2-3 个:

let response = await Specials.aggregate([
    {
        $match: { zip: zip }
    },
    {
        $lookup: {
            from: "products",
            let: { product_id: "$product_id" },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $and: [
                                {
                                    _id: "$$product_id"
                                },
                                {
                                    $or: [
                                        {
                                            name: filter
                                        },
                                        {
                                            country: filter
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                }
            ],
            as: "product"
        }
    },
    {
        $unwind: "$product"
    }
])

【问题讨论】:

  • 关于您在这里缺少的基本内容是您已经创建了局部变量product_id,但您没有将它与products 集合中的_id 匹配!!不需要吗?
  • 试试这个 :: { $match: { $expr: { $eq: ["$$product_id", "$_id"], { $or: [ { $eq: ["$name", ''], }, { $eq: ["$country", ''], }, ] } } }
  • 无权访问lappy,将'$eq'和'$or'都包裹在'$and'中..
  • 啊好吧,效果很好!这是完全有道理的。如果您想用正确的管道回答问题,我可以接受,或者我可以自己写答案并@你
  • 除了你给我的解决方案正则表达式效果很好,谢谢!

标签: mongodb aggregation-framework


【解决方案1】:

如果您使用的是 Mongo 4.2+ 版本,您可以使用 $regexMatch

let response = await Specials.aggregate([
    {
        $lookup: {
            from: "products",
            let: { product_id: "$product_id" },
            pipeline: [
                {
                    $match: {
                       $expr: {
                            $and: [
                                {
                                    $eq: ["$$product_id", "$_id"]
                                },
                                {
                                    $or: [
                                        {
                                            $regexMatch: { input: "$name", regex: filterRegex }
                                        },
                                        {
                                            $regexMatch: { input: "$country", regex: filterRegex }
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                }
            ],
            as: "product"
        }
    },
    {
        $unwind: "$product"
    },
    {
        $match: {
            $and: [
                {
                    zip: zip
                }
            ]
        }
    }
])

return response;

【讨论】:

  • 抛出“无法识别的表达式'$regexMatch'”错误。在我的 package.json 中,我的 Mongodb 版本是 3.5.8。我跑了 npm install --save mongodb@latest 这就是安装包
  • 嗯 3.5
  • 我知道。我无法通过 npm 安装最新版本,我误解了这一点。但是,我能够使用 $regex 找到解决方案。感谢您花时间为我写一个最新版本的解决方案,尽管我将来肯定会使用 $regexMatch
  • 澄清一下,通过 npm 安装 mongo 安装的是 nodejs 驱动,实际的 Mongo 版本是通过其他方式安装的,比如brewyum 等...
【解决方案2】:

这是我能够开始工作的以下解决方案:

let response = await Specials.aggregate([
    {
        $lookup: {
            from: "products",
            let: { product_id: "$product_id" },
            pipeline: [
                {
                    $match: {
                        $and: [
                            {
                                $or: [
                                    {
                                        name: { $regex: filter }
                                    },
                                    {
                                        country: { $regex: filter }
                                    }
                                ]
                            },
                            {
                                $expr: {
                                    $eq: ["$$product_id", "$_id"]
                                }
                            }
                        ]
                    }
                }
            ],
            as: "product"
        }
    },
    {
        $unwind: "$product"
    },
    {
        $match: {
            $and: [
                {
                    zip: zip
                }
            ]
        }
    }
])

return response;

** 使用有效的 $regex 实现进行了更新

【讨论】:

    猜你喜欢
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 2017-08-21
    • 1970-01-01
    • 2022-07-09
    • 2016-11-14
    • 1970-01-01
    • 2017-01-31
    相关资源
    最近更新 更多