【问题标题】:$match in $lookup result$查找结果中的 $match
【发布时间】:2017-06-24 18:29:17
【问题描述】:

我有下一个 mongo 代码:

db.users.aggregate([
    { 
        $match: { 
            $and: [
                { UserName: { $eq: 'administrator' } }, 
                { 'Company.CompanyName': { $eq: 'test' } }
            ]                   
        } 
    },
    { 
        $lookup: { 
            from: "companies", 
            localField: "CompanyID", 
            foreignField: "CompanyID", 
            as: "Company" 
        } 
    },
])

代码的$lookup 部分运行良好。我得到了下一个结果:

但是如果我在代码中添加$match,它什么也不会带来。

我发现问题出在第二个匹配:{ 'Company.CompanyName': { $eq: 'test' } },但我无法意识到它有什么问题。 有什么想法吗?

更新:

我也曾在$lookup 结果上尝试过$unwind,但没有运气:

db.users.aggregate([
    { 
        $match: { 
            $and: [
                { UserName: { $eq: 'administrator' } }, 
                { 'Company.CompanyName': { $eq: 'edt5' } }
            ] 
        } 
    },
    {   unwind: '$Company' },
    { 
        $lookup: { 
            from: 'companies', 
            localField: 'CompanyID', 
            foreignField: 'CompanyID', 
            as: 'Company' 
        } 
    },
])

【问题讨论】:

  • 两点: 1:您可以复制您认为应该返回的记录的示例吗?您的屏幕截图并不理想,因为在显示 CompanyName 字段之前公司数据已被截断 2:如果您仅使用 $match 部分运行,即没有 $unwind 或 $lookup,您会遇到同样的问题吗?
  • @VinceBowdren 1) 添加了带有完整公司对象的新图像。2) 与用户名匹配的 $match 仅运行良好,但公司字段仅使用查找,那么我如何在没有 $lookup 的情况下对其进行测试?
  • 您需要在 $lookup 之后 $unwind Company。 $unwind 之后在 company 字段上添加 $match 阶段
  • @AlexBerd chridam 的答案与您的版本相符。
  • @Veeram 你的评论也很有帮助

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

使用 MongoDB 3.4,您可以运行聚合管道,该管道使用 $addFields 管道和 $filter 运算符仅返回带有元素的 Company 数组符合给定条件的。然后,您可以使用 $arrayElemAt 运算符包装 $filter 表达式,以返回实质上包含 $unwind 功能的单个文档通过展平数组。

按照这个例子来理解上面的概念:

db.users.aggregate([
    { "$match": { "UserName": "administrator" } },
    { 
        "$lookup": { 
            "from": 'companies', 
            "localField": 'CompanyID', 
            "foreignField": 'CompanyID', 
            "as": 'Company' 
        } 
    },
    {
        "$addFields": {
            "Company": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$Company",
                            "as": "comp",
                            "cond": {
                                "$eq": [ "$$comp.CompanyName", "edt5" ]
                            }
                        }
                    }, 0
                ]
            }
        }
    }
])

【讨论】:

  • 你打败了我。您可能需要在查找后移动 $addFields 阶段并从 $match 中删除 CompanyName 部分。我认为CompanyName 是查找集合中的字段
  • @Veeram 你是对的,感谢您的关注。我已经更新了答案以包含 OP 的原始所需查询。干杯!
【解决方案2】:

以下答案适用于 mongoDB 3.6 或更高版本。

鉴于:

  • 您有一个集合 users 和一个字段 CompanyID 和一个集合 companies 和一个字段 CompanyID
  • 您想通过匹配CompanyIDUsers 上查找Companies,另外:

    • 每个用户必须匹配条件:User.UserName 等于 administrator
    • User 上的每个 Company 必须匹配条件:CompanyName 等于 edt5

以下查询将适用于您:

  db.users.aggregate([
    { $match: { UserName: 'administrator' } },
    {
      $lookup: {
        from: 'companies',
        as: 'Company',
        let: { CompanyID: '$CompanyID' },
        pipeline: [
          {
            $match: {
              $expr: {
                $and: [
                  { $eq: ['$CompanyID', '$$CompanyID'] },
                  { $eq: ['$CompanyName', 'edt5'] },
                ]
              }
            }
          }
        ]
      }
    },
  ])

解释: 这是使用比简单的外部/本地字段相等匹配更复杂的条件执行左连接查询的方法。

您不使用localFieldforeignField,而是使用:

  • let 可以将本地字段映射到变量的选项,
  • pipeline 选项,您可以在其中指定聚合 Array

pipeline 中,您可以使用$match 过滤器和$expr,在那里您可以重用之前在let 中定义的变量。

More info on $lookup

Nice tutorial

【讨论】:

  • 关于{ $eq: ['$CompanyID', '$$CompanyID'] },。左边是companies中的字段
  • 这提供了比应有的更多结果
  • 感谢所有的解释。这个答案确实是使用最新版本的最佳方法。
【解决方案3】:

这是在查找中过滤数组的代码。

 const userId = req.userData.userId;
const limit = parseInt(req.params.limit);
const page = parseInt(req.params.page);

Collection.aggregate([
 { $match: {} },
  { $sort: { count: -1 } },
  { $skip: limit * page },
  { $limit: limit },
  {
    $lookup: {
      from: Preference.collection.name,
      let: { keywordId: "$_id" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $eq: ["$keyword", "$$keywordId"] },
                {
                  $eq: ["$user", mongoose.Types.ObjectId(userId)],
                },
              ],
            },
          },
        },
      ],
      as: "keywordData",
    },
  },
  {
    $project: {
      _id: 0,
      id: "$_id",
      count: 1,
      for: 1,
      against: 1,
      created_at: 1,
      updated_at: 1,
      keyword: 1,
      selected: {
        $cond: {
          if: {
            $eq: [{ $size: "$keywordData" }, 0],
          },
          then: false,
          else: true,
        },
      },
    },
  }])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 2020-01-08
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    相关资源
    最近更新 更多