在单个集合上使用mongodb $ lookup

时间:2016-07-01 07:24:38

标签: mongodb lookup

我有一个包含这样的文档的集合

{
    "_id" : ObjectId("5773ac6a486f811694711875"),
    "bsk" : {
        "bskItems" : [ 
            {
                "id" : 4,
                "bskItemLineType" : "SaleItem",
                "product" : {
                    "description" : "reblochon"
                }
            }, 
            {
                "id" : 5,
                "bskItemLineType" : "SaleItem",
                "product" : {
                    "description" : "Pinot Noir"
                }
            }, 
            {
                "id" : 13,
                "bskItemLineType" : "PromotionItem",
                "promotionApplied" : {
                    "bskIds" : [ 
                        4, 
                        5
                    ]
                }
            }, 
            {
                "id" : 8,
                "bskItemLineType" : "SaleItem",
                "product" : {
                    "description" : "Food"
                }
            }, 
            {
                "id" : 10,
                "bskItemLineType" : "SubTotalItem"
            }, 
            {
                "id" : 12,
                "bskItemLineType" : "TenderItem"
            }, 
            {
                "id" : 14,
                "bskItemLineType" : "ChangeDue"
            }
        ]
    }
}

我想要一个输出,我可以看到“promotionsApplied”以及它们应用的项目的描述。对于上面的文档,“promotionsApplied”是“bsk.BskItems.id”4和5所以我希望输出为:

{
    "_id": xxxxx,
    "promotionAppliedto : "reblochon"
},
{

    "_id": xxxxx,
    "promotionAppliedto : "Pinot Noir"
}      

以下查询:

 db.getCollection('DSTest').aggregate([
{$project:{"bsk.bskItems.product.description":1,"bsk.bskItems.id":1}},
{$unwind: "$bsk.bskItems"},

    ])

给我说明

db.getCollection('DSTest').aggregate([
{$project:{"bsk.bskItems.promotionApplied.bskIds":1}},

{$unwind: "$bsk.bskItems"},
{$unwind:"$bsk.bskItems.promotionApplied.bskIds"},

    ])

让我获得促销活动。我希望能够使用$lookup根据_idbsk.bskItems.promotionApplied.bskIds以及_idbsk.bskItems.id加入这两者,但我无法弄清楚如何。

2 个答案:

答案 0 :(得分:1)

我不知道你是否解决了问题,或者这是否相关,但我想出了你的问题:

db.DSTest.aggregate([
{
  $unwind: "$bsk.bskItems"
},
{
  $project: {
    baItId: { $ifNull: [ "$bsk.bskItems.id", 0 ] },
    "bsk": { 
      "bskItems": {
        "promotionApplied": {
          "bskIds": { $ifNull: [ "$bsk.bskItems.promotionApplied.bskIds", [0] ] }
          }
        }
      },
      "product": { $ifNull: [ "$bsk.bskItems.product.description", "" ] },
    }
},
{
  $unwind: "$bsk.bskItems.promotionApplied.bskIds"
},
{
  $project: {
     baItId: 1,
     proAppliedId: 
     {
       $cond: { if: { $eq: [ "$bsk.bskItems.promotionApplied.bskIds", 0 ] }, then: "$baItId", else: "$bsk.bskItems.promotionApplied.bskIds" }
     }, 
     product: 1
  }
}, 
{
  $group: {
    _id: { proAppliedId: "$proAppliedId", docId: "$_id"},
    product: { $push:  { "p": "$product" } },
    groupCount: { $sum: 1 }
  }
},
{
  $unwind: "$product"
},
{
  $match: {
    "product.p": {$ne: ""}, "groupCount": { $gt: 1}
  }
},
{
  $project: {
    _id: "$_id.docId",
    "promotionAppliedto": "$product.p"
  }
}
])

使用虚拟文档,这是我得到的结果:

{ 
    "_id" : ObjectId("5773ac6a486f811694711875"), 
    "promotionAppliedto" : "reblochon"
}
{ 
    "_id" : ObjectId("5773ac6a486f811694711875"), 
    "promotionAppliedto" : "Pinot Noir"
}

但我的建议是下次在你的数据库结构中加入一些思考。你有苹果和梨,所以我们必须做一个亚洲梨才能得到这个结果。同样从聚合级别看,这不是一件容易的事。如果您将包含字段product的数组与包含字段promotionApplied的数组分开,那可能会容易得多。

要分解并逐步解释发生的事情:

{
  $unwind: "$bsk.bskItems"
}

通过展开,我们正在展平我们的阵列。我们需要这个来访问数组中的字段并对它们进行操作。有关$unwind

的更多信息
{
  $project: {
    baItId: { $ifNull: [ "$bsk.bskItems.id", 0 ] },
    "bsk": { 
      "bskItems": {
        "promotionApplied": {
          "bskIds": { $ifNull: [ "$bsk.bskItems.promotionApplied.bskIds", [0] ] }
          }
        }
      },
      "product": { $ifNull: [ "$bsk.bskItems.product.description", "" ] },
    }
}

baItId: { $ifNull: [ "$bsk.bskItems.id", 0 ] }

通过这一行,我们只需确保每个文档都获得一个篮子项ID。在你的情况下他们都这样做,我只是添加它以确保。如果某个文档没有该字段的值,我们将其设置为0(您可以将其设置为-1或任何您想要的值)

"bsk": { 
  "bskItems": {
    "promotionApplied": {
      "bskIds": { $ifNull: [ "$bsk.bskItems.promotionApplied.bskIds", [0] ] }
      }
    }
  }

我们在这里为字段"$bsk.bskItems.promotionApplied.bskIds"创建一个数组。由于并非所有文档都有此字段,我们必须将它们全部添加到其中,否则我们会将橙子与苹果进行比较。

"product": { $ifNull: [ "$bsk.bskItems.product.description", "" ] }

如前所述,我们必须使我们的文档看起来完全相同,因此我们还将$bsk.bskItems.product.description添加到没有此字段的文档中。那些没有字段的人我们将其设置为空字符串

现在我们所有的文档都具有相同的结构,我们可以从实际的整理开始。

{
  $unwind: "$bsk.bskItems.promotionApplied.bskIds"
}

由于我们想要访问$bsk.bskItems.promotionApplied.bskIds内的ID,我们也必须解开这个数组。

{
  $project: {
     baItId: 1,
     proAppliedId: 
     {
       $cond: { if: { $eq: [ "$bsk.bskItems.promotionApplied.bskIds", 0 ] }, then: "$baItId", else: "$bsk.bskItems.promotionApplied.bskIds" }
     }, 
     product: 1
  }
}

baItId: 1product: 1正在传递中。 proAppliedId将包含我们的bsk.bskItems.promotionApplied.bskIds。如果它们为0,则获得与字段$baItId相同的ID,否则它们会保留其ID。

{
  $group: {
    _id: { proAppliedId: "$proAppliedId", docId: "$_id"},
    product: { $push:  { "p": "$product" } },
    groupCount: { $sum: 1 }
  }
}

现在我们终于可以按照我们在前一个聚合管道中创建的$proAppliedId对文档进行分组。 我们还将产品值推送到数组中。所以现在将有包含两个条目的数组。 一个具有我们查找的值,另一个具有空字符串,因为我们在之前的聚合管道"product": { $ifNull: [ "$bsk.bskItems.product.description", "" ] }中执行了该操作 我们还创建了一个名为groupCount的新字段来计算组合在一起的文档。

{   $project: {
    _id: "$_id.docId",
    "promotionAppliedto": "$product.p"   } }

在最终项目中,我们只是按照我们希望的样子来构建最终文档。

希望你现在明白为什么思考,是和我们如何拯救事物,重要。

答案 1 :(得分:0)

使用文档类型数据库 - 最好存储促销metadtaa而不是id。 请参阅附件中的例子

"promotionApplied" : [{
        bskId : 4,
        name : "name",
        otherData : "otherData"
    }, {
        bskId : 5,
        name : "name5",
        otherData : "otherData5"
    }
]