MongoDB聚合-查找管道不返回任何文档

时间:2020-01-18 14:46:52

标签: mongodb aggregation-framework

我很难将$lookuppipeline一起用于MongoDB Compass。

我有以下收藏:

玩具

First Image - Toys

数据

[
  {
    "_id": {
      "$oid": "5d233c3bb173a546386c59bb"
    },
    "type": "multiple",
    "tags": [
      ""
    ],
    "searchFields": [
      "Jungle Stampers - Two",
      ""
    ],
    "items": [
      {
        "$oid": "5d233c3cb173a546386c59bd"
      },
      {
        "$oid": "5d233c3cb173a546386c59be"
      },
      {
        "$oid": "5d233c3cb173a546386c59bf"
      },
      {
        "$oid": "5d233c3cb173a546386c59c0"
      },
      {
        "$oid": "5d233c3cb173a546386c59c1"
      },
      {
        "$oid": "5d233c3cb173a546386c59c2"
      },
      {
        "$oid": "5d233c3cb173a546386c59c3"
      },
      {
        "$oid": "5d233c3cb173a546386c59c4"
      }
    ],
    "name": "Jungle Stampers - Two",
    "description": "",
    "status": "active",
    "category": {
      "$oid": "5cfe727cac920000086b880e"
    },
    "subCategory": "Stamp Sets",
    "make": "",
    "defaultCharge": null,
    "defaultOverdue": null,
    "sizeCategory": {
      "$oid": "5d0cfde57561e107c88fbde3"
    },
    "ageFrom": {
      "$numberInt": "24"
    },
    "ageTo": {
      "$numberInt": "120"
    },
    "images": [
      {
        "_id": {
          "$oid": "5d233c3bb173a546386c59bc"
        },
        "id": {
          "$oid": "5d233c39b173a546386c59ba"
        },
        "url": "/toyimages/5d233c39b173a546386c59ba.jpg",
        "thumbUrl": "/toyimages/thumbs/tn_5d233c39b173a546386c59ba.jpg"
      }
    ],
    "__v": {
      "$numberInt": "2"
    }
  }
]

贷款

Second Image - Loans

数据

[
  {
    "_id": {
      "$oid": "5e1f1661b712215978c746d9"
    },
    "tags": [],
    "member": {
      "$oid": "5e17495e4f81ab3f900dbb63"
    },
    "source": "admin portal - potter1@gmail.com",
    "items": [
      {
        "id": {
          "$oid": "5e1f160eb712215978c746d5"
        },
        "status": "new",
        "_id": {
          "$oid": "5e1f1661b712215978c746db"
        },
        "toy": {
          "$oid": "5d233c3bb173a546386c59bb"
        },
        "cost": {
          "$numberInt": "0"
        }
      },
      {
        "id": {
          "$oid": "5e1f160eb712215978c746d5"
        },
        "status": "new",
        "_id": {
          "$oid": "5e1f1661b712215978c746da"
        },
        "toy": {
          "$oid": "5d233b1ab173a546386c59b5"
        },
        "cost": {
          "$numberInt": "0"
        }
      }
    ],
    "dateEntered": {
      "$date": {
        "$numberLong": "1579095632870"
      }
    },
    "dateDue": {
      "$date": {
        "$numberLong": "1579651200000"
      }
    },
    "__v": {
      "$numberInt": "0"
    }
  }
]

我正在尝试返回状态为“新”或“出”的玩具及其相关贷款清单。

我可以使用以下$lookup汇总来获取所有贷款:

{
  from: 'loans',
  localField: '_id',
  foreignField: 'items.toy',
  as: 'loansSimple'
}

但是,我试图使用管道来加载具有我感兴趣的两种状态的贷款,但是它始终只返回零个文档:

{
  from: 'loans',
  let: {
    'toyid': '$_id'
  },
  pipeline: [
    {
      $match: {
        $expr: {
          $and: [
            {$eq: ['$items.toy', '$$toyid']},
            {$eq: ['$items.status', 'new']} // changed from $in to $eq for simplicity
          ]
        }
      }
    }  
  ],
  as: 'loans'
}

这似乎总是返回0个文档,但是我安排了它:

Image Three - Results

我在某个地方犯了错误吗?

我正在使用MongoDB Atlas,v4.2.2,MongoDB Compass v 1.20.4

2 个答案:

答案 0 :(得分:1)

您正在尝试在内部数组中搜索<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css"> </head> <body style="background-color:#eeeeee;padding:25px;"> <div class="card-columns"> <div class="card" style="width:200;height:200px;border:none;padding-right:20px;padding-left:20px"> <div class="card-body"> <h5 class="card-title">Card title</h5> <p class="card-text">This is another card with title and supporting text below. This card has some additional content to make it slightly taller overall.</p> </div> </div> <div class="card" style="width:800px;height:200px;position:relative;border:none;padding-right:20px;padding-left:20px"> <div style="width:60px;height:60px;background-color:#eeeeee;position:absolute;top:70px;left:-40px;text-align:center;line-height:60px;"><i class="fas fa-arrow-right" style="font-size:22px"></i></div> <div class="card-body"> <h5 class="card-title">Card title</h5> <p class="card-text">This is another card with title and supporting text below. This card has some additional content to make it slightly taller overall.</p> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> </body> </html> ,但是运算符表达式$$toyid无法解析它。

最佳解决方案: $eq(按条件返回过滤的$let)+ loans(对内部数组应用过滤器)运算符可帮助我们获得所需的结果。

$filter

MongoPlayground

替代解决方案1。使用db.toys.aggregate([ { $lookup: { from: "loans", let: { "toyid": "$_id", "toystatus": "new" }, pipeline: [ { $match: { $expr: { $gt: [ { $size: { $let: { vars: { item: { $filter: { input: "$items", as: "tmp", cond: { $and: [ { $eq: [ "$$tmp.toy", "$$toyid" ] }, { $eq: [ "$$tmp.status", "$$toystatus" ] } ] } } } }, in: "$$item" } } }, 0 ] } } } ], as: "loans" } } ]) 展平$unwind属性。 (我们创建了一个名为items的额外字段,用于存储tmp的值,使用items运算符将其展平,按照您的操作进行匹配,然后从结果中排除)

$unwind

MongoPlayground

替代解决方案2 。我们使用db.toys.aggregate([ { $lookup: { from: "loans", let: { "toyid": "$_id" }, pipeline: [ { $addFields: { tmp: "$items" } }, { $unwind: "$tmp" }, { $match: { $expr: { $and: [ { $eq: [ "$tmp.toy", "$$toyid" ] }, { $eq: [ "$tmp.status", "new" ] } ] } } }, { $project: { tmp: 0 } } ], as: "loans" } } ]) 创建玩具的数组,并使用$reduce运算符检查该数组内是否存在$in

toyid

答案 1 :(得分:1)

$expr收到aggregation expressions,到那时,$$items.toy会按照您的期望为数组中的每个元素进行解析(但是,如果这样做,它仍然会给您“不好的”结果,您将获得包含所需玩具ID和其他任何在其项数组中状态为new的项的贷款。

因此,您可以通过两种方法解决此问题:

  1. 如果您不关心查找文档中的其他项目,则可以在查找管道的开始处添加一个$unwind阶段,如下所示:
{
    from: 'loans',
    let: {
        'toyid': '$_id'
    },
    pipeline: [
        {
            $unwind: "$items"
        },
        {
            $match: {
                $expr: {
                    $and: [
                        {$eq: ['$items.toy', '$$toyid']},
                        {$eq: ['$items.status', 'new']} // changed from $in to $eq for simplicity
                    ]
                }
            }
        }
    ],
    as: 'loans'
}
  1. 如果您确实关心它们,只需以一种可能的方式迭代数组即可获得“正确”匹配,这是使用$filter
  2. 的示例
    {
        from: 'loads',
        let: {
            'toyid': '$_id'
        },
        pipeline: [
            {
                $addFields: {
                    temp: {
                        $filter: {
                            input: "$items",
                            as: "item",
                            cond: {
                                $and: [
                                    {$eq: ["$$item.toy", "$$toyid"]},
                                    {$eq: ["$$item.status", "new"]}
                                ]
                            }
                        }


                    }
                }

            }, {$match: {"temp.0": {exists: true}}}
        ],
        as: 'loans'
    }