简体   繁体   中英

Mongodb many-to-many get related items

I have 3 mongodb collection with many to many relation, productfeatures collection is the relation collection.

db={
  "products": [
    {
      "id": 1,
      "name": "product 1"
    }
  ],
  "features": [
    {
      "id": 101,
      "name": "width"
    },
    {
      "id": 102,
      "name": "length"
    },
    {
      "id": 103,
      "name": "height"
    }
  ],
  "productfeatures": [
    {
      "productId": 1,
      "featureId": 101,
      "value": "3"
    },
    {
      "productId": 1,
      "featureId": 102,
      "value": "4"
    },
    {
      "productId": 1,
      "featureId": 103,
      "value": "5"
    }
  ]
}

I want to get a product's all features like the following, how can this be done?

[
  {
    "id": 1,
    "name": "product 1",
    "productfeatures": [
        {
        "feature": "width",
        "value": "3"
      },
      {
        "feature": "length",
        "value": "4"
      },
      {
        "feature": "height",
        "value": "5"
      }
    ]
  }
]

I know how to get the productfeatures with lookup stage:

db.products.aggregate([
  {
    $match: {
      id: 1
    }
  },
  {
    $lookup: {
      from: "productfeatures",
      localField: "id",
      foreignField: "productId",
      as: "productfeatures"
    }
  }
])

But I also want to join to the features collection to get the feature name.

https://mongoplayground.net/p/J-20zxxFW5q

You can use mongodb aggregation pipeline with multiple $lookup stage to achieve this.

You were going on the right path, You needed to add one $unwind stage(to unwind the result of first lookup stage) and $lookup stage, and finally to group all the results, you would need a final $group stage, to combine all features in one array.

Try this :

db.products.aggregate([
    {
        $match: {
            id: 1
        }
    },
    {
        $lookup: {
            from: "productfeatures",
            localField: "id",
            foreignField: "productId",
            as: "productfeatures"
        }
    },{
        $unwind : "$productfeatures"
    },{
        $lookup : {
            from : "features",
            local : "productfeatures.featureId",
            foreignField : "id",
            as : "feature"
        }
    },{
        $unwind : "$feature"
    },{
        $group : {
            _id : "$_id",
            name : {$first : "$name"},
            productfeatures : {$push : "$feature"}

        }
    }
])

Please read about $group , $unwind , $lookup for more details.

You can use below aggregation

db.products.aggregate([
  { "$match": { "id": 1 }},
  { "$lookup": {
    "from": "productfeatures",
    "let": { "productId": "$id" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": ["$$productId", "$productId"] }}},
      { "$lookup": {
        "from": "features",
        "let": { "featureId": "$featureId" },
        "pipeline": [
          { "$match": { "$expr": { "$eq": ["$id", "$$featureId"] }}}
        ],
        "as": "productfeatures"
      }},
      { "$project": {
        "value": 1,
        "feature": { "$arrayElemAt": ["$productfeatures.name", 0] }
      }}
    ],
    "as": "productfeatures"
  }}
])

MongoPlayground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM