Mongodb многие ко многим получают связанные предметы - PullRequest
3 голосов
/ 07 июля 2019

У меня есть 3 коллекции mongodb со многими ко многим, Коллекция productfeatures - это коллекция отношений.

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"
    }
  ]
}

Я хочу получить все функции продукта, например, как это можно сделать?

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

Я знаю, как получить особенности продукта со стадией поиска:

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

Но я также хочу присоединиться к коллекции функций, чтобы получить имя функции.

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

Ответы [ 2 ]

1 голос
/ 07 июля 2019

Вы можете использовать ниже агрегации

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

1 голос
/ 07 июля 2019

Вы можете использовать mongodb aggregation pipeline с несколькими $lookup этапами для достижения этой цели.

Вы шли по правильному пути, вам нужно было добавить один $unwind этап (чтобы развернуть результат первого lookup этап) и $lookup этап, и, наконец, для группировки всех результатов вам потребуется заключительный этап $group, чтобы объединить все функции в одном массиве.

Попробуйте это:

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"}

        }
    }
])

Пожалуйста, прочитайте о $ group , $ unwind , $ lookup для более подробной информации.

...