如何使用聚合管道查找未在售但存在于产品详细信息集合中的产品的 ID

How to find ids for products that are not on sale but exist in the product details collection using aggregation pipeline

提问人:BreenDeen 提问时间:11/10/2023 最后编辑:BreenDeen 更新时间:11/14/2023 访问量:130

问:

我正在加入 productDetail 集合上的产品集合,其中产品_id是 productDetail 集合中的_id。我希望能够找到未在售但存在于 productDetail 表中的产品,以作为 inProductDetailCollection 包含在我的输出中,以便进行报告。我试了一下,但它不起作用。即使某些_ids不在 productDetail 表中,它也始终返回 true。这是我的尝试。我怎样才能让它将标志 inProductDetailCollection 设置为 false(如果缺失)或 true(如果存在)


     db.getCollection("products").aggregate([
      {
        "$match": {
          "onSale": {
            "$exists": false
          }
        }
      },
      {
        "$lookup": {
          "from": "productDetail",
          "localField": "_id",
          "foreignField": "_id",
          "as": "productDetail"
        }
      },
      {
        "$match": {
          "$expr": {
            "$eq": [
              "$productDetail",
              []
            ]
          }
        }
      },
     
      {
        "$unwind": {
          "path": "$productDetail",
          "preserveNullAndEmptyArrays": true
        }
      },
      {
  
        "$addFields": {
          "onSale": false
        }
      },
      {
        "$group": {
          "_id": {
            "productId": "$_id",
            "onSale": "$onSale"
          }
        }
      },
      {
        "$project": {
          "productId": "$_id.productId",
          "onSale": "$_id.onSale",
          "inProductDetailCollection":
           {
                 $cond: { if: { $gt: [ "_id", 0 ] }, then: true, else: false }
          },  
          "_id": 0
        }
      }
    ]
  )

下面是数据示例。需要注意的一点是,productDetail 表中的产品可能没有_ids,因为此表是由夜间批处理作业上传的。此外,未打折的商品将没有“onSale”: “Y” 属性。数据如下所示:


    //products collection, some fields omitted for brevity

    [
      {
       "_id": 123345,
       "name": "NutraFast",
       "description": "Supplement",
       "price": 35.99
     },
     { 
       "_id": 13443,
       "name": "BerryBlast",
       "description": "Athletes Sports Drink",
       "price": 12.99
      },
      {
       "_id": 15644
       "name": "MagnoPower-11",
       "description": "Supplement",
       "price": 45.99
      }
     ,{
       "_id": 17011
       "name": "Zinc566",
       "description": "Supplement",
       "price": 25.99
     },
     {
       "_id": 15011
       "name": "VitaMax",
       "description": "Supplement",
       "price": 15.99
      },
      {
       "_id": 15311
        "name": "VitaMax",
         "description": "Supplement",
         "price": 15.99
       },
      { 
        "_id": 15316
        "name": "Chlorphyl Cleanse",
        "description": "Supplement",
        "price": 55.99
      }
     ]

下面是 productDetail 集合示例


      //productDetail collection
      [
        {
         "_id": 123345,
         "discount": 0.3,
         "amount-per-unit": 50,
         "inStock": "Y"
       },
      {
        "_id": 13443,
        "discount": 0.5,
        "onSale": "Y",
        "amount-per-unit": 60,
        "inStock": "Y"
        "onSale":"Y"
      },
      {
        "_id" : 15644,
        "discount": 0.5,
        "onSale": "Y",
        "amount-per-unit": 60,
        "inStock": "Y"
      },

      {
        "_id" : 15011,
        "discount": 0.5,
        "amount-per-unit": 60,
        "inStock": "Y"
      },

      {
        "_id" : 17011,
        "discount": 0.5,
        "amount-per-unit": 60,
        "inStock": "Y"
      } 

    ]



mongoDB 聚合框架

评论

2赞 jQueeny 11/10/2023
来自和集合的示例文档将有很大帮助。你能把它们贴出来吗?productsproductDetail
0赞 aneroid 11/10/2023
如果没有这两个集合的示例数据,我们只能猜测查询应该是什么。此外,在将查询结果添加到问题后,添加这些示例文档的查询预期结果。我假设 & 是 1 对 1,因为您对两者都使用相同的。productproductDetail_id
0赞 BreenDeen 11/10/2023
我添加了一个字段的子集,因为它是大量的字段。谢谢
0赞 cmgchess 11/10/2023
您的数据集是否正确 mongoplayground.net/p/BGF7oXU87Y - 例如,产品中有重复的 onSale 和重复的_id
0赞 BreenDeen 11/10/2023
我更正了最后_id。

答:

2赞 jQueeny 11/13/2023 #1

很难理解你真正需要什么。但是,我冒昧地更正了示例文档中的一些无效对象结构,以下是两种可能的聚合,希望能为您提供所需的输出:

示例 1

这将返回具有以下条件的文档:products

  • 匹配productDetail
  • 使用包含文档的名为productDetail$lookup
  • 带有名为inProductDetailCollectionButNotOnSale
  • 这只有在打折的情况下才会出现trueproduct
  • 或其他方式false
db.getCollection("products").aggregate([
  {
    $lookup: {
      from: "productDetail",
      localField: "_id",
      foreignField: "_id",
      as: "productDetail"
    }
  },
  {
    $unwind: {
      path: "$productDetail"
    }
  },
  {
    $set: {
      inProductDetailCollectionButNotOnSale: {
        $cond: [
          {
            $eq: [
              "$productDetail.onSale",
              "Y"
            ]
          },
          false,
          true
        ]
      }
    }
  }
])

有关工作示例,请参见 此处


示例 2

这将返回所有文件,包括:products

  • 包含文档(如果有)的字段productDetail$lookup
  • 带有名为inProductDetailCollectionButNotOnSale
  • 只有当有匹配并且打折时才会有trueproductproductDetail
  • 或其他方式false
db.getCollection("products").aggregate([
  {
    $lookup: {
      from: "productDetail",
      localField: "_id",
      foreignField: "_id",
      as: "productDetail"
    }
  },
  {
    $unwind: {
      path: "$productDetail",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $set: {
      inProductDetailCollectionButNotOnSale: {
        $cond: [
          {
            $and: [
              {
                $gt: [
                  "$productDetail",
                  0
                ]
              },
              {
                $ne: [
                  "$productDetail.onSale",
                  "Y"
                ]
              }
            ]
          },
          true,
          false
        ]
      }
    }
  }
])

有关工作示例,请参见 此处

注意:为清楚起见,如果其他人想知道为什么这部分工作:

$gt: [
   "$productDetail",
   0
]

Mongodb 有一个比较/排序顺序,它按从低到高的顺序列出 BSON 类型。我所做的是将该字段与 .由于在列表中排名第 4 位,在列表中排名第 3,这基本上意味着如果文档中存在,那么它将位于第 4 级,高于 () 高于列表中第 3 级的数字零。$productDetailNumberObjectNumber$productDetail$gt

它返回 true,因为它实质上转换为:

$gt: [
   4, // 4 is greater than 3
   3
]

如果不存在,则它将返回 false,因为 a 位于第 2 级,而高于第 3 级,因此它转换为:$productDetailnullNumber

$gt: [
   2, // 2 is NOT greater than 3
   3
]

评论

0赞 BreenDeen 11/13/2023
您能解释一下这部分在$and中的含义吗?$gt: [ “$productDetail”, 0 ]
0赞 BreenDeen 11/13/2023
非常感谢您的解决方案。我尝试了各种解决方案,但它们就是不起作用,所以我非常感谢这个解决方案
0赞 jQueeny 11/13/2023
@BreenDeen因为 productDetail 是一个添加的数组字段,然后展开该字段,因此该条件基本上会检查它是否存在。因为有些文档没有它(没有匹配的 productDetail 文档的文档),所以我们需要它们为 false。如果 productDetail 存在,则该$and部分将为 true。
0赞 jQueeny 11/14/2023
@BreenDeen 我已经添加了关于为什么该部分有效的解释。