【问题标题】:How to access the fields from arrays of a object in two different collections?如何从两个不同集合中的对象数组中访问字段?
【发布时间】:2017-10-25 10:30:00
【问题描述】:

这是locations收集数据。

{
  _id: "1",
  location: "loc1",
  sublocations: [
    {
      _id: 2,
      sublocation: "subloc1",
    },
    {
      _id: 3,
      sublocation: "subloc2",
    }
  ]
},
{
  _id: "4",
  location: "loc2",
  sublocations: [
    {
      _id: 5,
      sublocation: "subloc1",
    },
    {
      _id: 6,
      sublocation: "subloc2",
    }
  ]
}

这是products收集数据

{
  _id: "1",
  product: "product1",
  prices: [
    {
      _id: 2,
      sublocationid: 2,        //ObjectId of object in sublocations array 
      price: 500
    },
    {
      _id: 3,
      sublocationid: 5,        //ObjectId of object in sublocations array
      price: 200
    }
  ]
}

现在我需要在价格数组的产品模式中获取sublocation。预期结果如下。

{
  _id: "1",
  product: "product1",
  prices: [
    {
      _id: 2,
      sublocationid: 3,
      sublocation: "subloc2", 
      price: 500
    },
    {
      _id: 3,
      sublocationid: 5,
      sublocation: "subloc1"
      price: 200
    }
  ]
}

为了实现它,我按照以下方式进行了操作。

  • 首先,对 locations 集合执行聚合 - $unwind 子位置数组并将 $out 存储在新集合中。
  • 其次,对“产品”集合执行聚合 - $unwind 价格,$lookup 从新集合中的 sublocationid 并将它们分组。
  • 第三,获取数据后删除新集合的数据。

还有其他简化的方法吗?有的话请告诉我。

【问题讨论】:

  • 您介意提供结果集的示例吗?这对于提供简化查询非常有帮助。
  • 另一个问题 - 子位置 ID 是全球唯一的吗?
  • 我提出了另一个问题 - 在价格数组中您将子位置 id 作为字符串而在子位置数组中作为整数是不是错字?
  • @cbartosiak,这只是一个错字。子位置 ID 是自动生成的对象 ID。我没有明确分配它们。只是举一个我给他们的例子。
  • 有一种更简单的方法,但它使用的是即将发布的 3.6 候选版本。如果您有兴趣,请告诉我,我可以将其添加为答案。

标签: mongodb


【解决方案1】:

如果你想坚持使用 3.4 版本,你可以试试这个查询:

db.products.aggregate([
    {
        $unwind: {
            "path": "$prices"
        }
    },
    {
        $lookup: {
            "from": "locations",
            "localField": "prices.sublocationid",
            "foreignField": "sublocations._id",
            "as": "locations"
        }
    },
    {
        $unwind: {
            "path": "$locations"
        }
    },
    {
        $unwind: {
            "path": "$locations.sublocations"
        }
    },
    {
        $addFields: {
            "keep": {
                "$eq": [
                    "$prices.sublocationid",
                    "$locations.sublocations._id"
                ]
            }
        }
    },
    {
        $match: {
            "keep": true
        }
    },
    {
        $addFields: {
            "price": {
                "_id": "$prices._id",
                "sublocationid": "$prices.sublocationid",
                "sublocation": "$locations.sublocations.sublocation",
                "price": "$prices.price"
            }
        }
    },
    {
        $group: {
            "_id": "$_id",
            "product": { "$first": "$product" },
            "prices": { "$addToSet": "$price" }
        }
    }
]);

虽然不如 3.6 版本好,因为内存消耗更高。

【讨论】:

    【解决方案2】:

    您可以在 3.6 版本中尝试以下聚合查询。

    由于本地字段和外部字段都是数组,您必须 $unwind 进行相等比较。

    为此,您必须使用新的$lookup 语法。

    $match$expr 提供文档字段之间的比较,以查找每个产品的子位置 ID 的位置子位置文档。

    $project 投影匹配的子位置文档。

    $addFields$arrayElemAt 将查找到的子位置数组转换为文档。

    $group 推送所有价格与每个产品的匹配子位置文档。

    db.products.aggregate[
      {
        "$unwind": "$prices"
      },
      {
        "$lookup": {
          "from": "locations",
          "let": {
            "prices": "$prices"
          },
          "pipeline": [
            {
              "$unwind": "$sublocations"
            },
            {
              "$match": {
                "$expr": [
                  "$$prices.sublocationid",
                  "$sublocations._id"
                ]
              }
            },
            {
              "$project": {
                "sublocations": 1,
                "_id": 0
              }
            }
          ],
          "as": "prices.sublocations"
        }
      },
      {
        "$addFields": {
          "prices.sublocations": {
            "$arrayElemAt": [
              "$prices.sublocations",
              0
            ]
          }
        }
      },
      {
        "$group": {
          "_id": "$_id",
          "product": {
            "$first": "$product"
          },
          "prices": {
            "$push": "$prices"
          }
        }
      }
    ])
    

    【讨论】:

      猜你喜欢
      • 2020-12-26
      • 1970-01-01
      • 2016-09-26
      • 2016-06-03
      • 1970-01-01
      • 2020-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多