Объединение двух коллекций в mongodb - PullRequest
1 голос
/ 03 мая 2019

У меня есть отдельные коллекции для «комментариев», «продуктов» и «пользователей».Коллекция 'comments' содержит текст, product_id и user_id.Когда продукт извлекается, я хочу получить сведения о продукте вместе с данными пользователя в результате.

Я создал схему, используя mongoose odm.Я использую функцию агрегирования, чтобы заполнить продукт комментариями с использованием $ lookup.

Product.aggregate([
        {
            $match:{
                _id:mongoose.Types.ObjectId(id)
            }
        },
        {
            $lookup: {
                from: "comments",
                localField: "_id",
                foreignField: "product",
                as: "comments"
            }
        },
        {
            $match:{
                "comments.product":mongoose.Types.ObjectId(id)
            }
        },
        {
            $lookup: {
                from: "users",
                localField: "comments.user._id",
                foreignField: "user",
                as: "comments.user"
            }
        }
])

ожидаемый результат

[
    {
        "_id": "5cc9441feed4c258881c99cd",
        "title": "Batman",
        "imageUrl": "images\\1556694047310_Batman.jpg",
        "price": 555,
        "description": "The dark knight",
        "user": "5cbca36d4acc5d538c209014",
        "__v": 2,
        "comments": [
                { 
                  "_id": "5cc947125c69600d58c1be05",
                  "date": "2019-05-01T07:12:42.229Z",
                  "text": "This product is very nice",
                  "user":{
                          "_id": "5cbca36d4acc5d538c209014",
                          "name": "Clark Kent"
                         }
                },
                {
                  "_id": "5cc96eb4b2834d43f8a24470",
                  "date": "2019-05-01T09:46:34.774Z",
                  "text": "Anyone can be Batman",
                  "user":{
                          "_id": "5cbca5504acc5d538c209015",
                          "name": "Bruce Wayne"
                         },
                }

    }
]

фактический результат

[
    {
        "_id": "5cc9441feed4c258881c99cd",
        "title": "Batman",
        "imageUrl": "images\\1556694047310_Batman.jpg",
        "price": 555,
        "description": "The dark knight",
        "user": "5cbca36d4acc5d538c209014",
        "__v": 2,
        "comments": {
            "user": [
                {
                    "_id": "5cbca5504acc5d538c209015",
                    "name": "Bruce Wayne",
                    "email": "batman@gotham.com",
                    "password": "$2a$12$L.t/nBXq/xlic25Y0a884uGxjlimuNH/tcmWLg.sNkcjJ/C40Q14m",
                    "contactNumber": 9999999999,
                    "address": "Somewhere in Gotham",
                    "__v": 0
                },
                {
                    "_id": "5cbca7334acc5d538c209016",
                    "name": "Superman",
                    "email": "superman@metro.com",
                    "password": "$2a$12$mrogzC1Am86b0DnvTzosm.qfu38Ue7RqSNcnVSoCR55PtmLddeZv.",
                    "contactNumber": 9999999999,
                    "address": "Somewhere in metropolis",
                    "__v": 0
                },
                {
                    "_id": "5cbca7e54acc5d538c209017",
                    "name": "Wonder Woman",
                    "email": "ww@amazon.com",
                    "password": "$2a$12$Vt9XZUyOTULvel5zNAsMLeoMi3HlaGJJZN7OH2XkWuoAiZtDIGaMq",
                    "contactNumber": 9999999999,
                    "address": "Somewhere in Amazon",
                    "__v": 0
                },
                {
                    "_id": "5cbe192934ae2944c8704a5a",
                    "name": "Barry Allen",
                    "email": "barry@flash.com",
                    "password": "$2a$12$k73Wp1HTMv/MhUV3BOok3OSh.nnLq3vWG1Qz9ZTO7iB7saFlxhLjW",
                    "contactNumber": 9999999999,
                    "address": "Somewhere in Central City",
                    "__v": 0
                }
            ]
        }
    }
]

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

Ваш $lookup запрос users перезаписывает массив comments.Он не работает так, как вы думаете.

Вам нужно развернуть массив комментариев, а затем запустить $lookup пользователей, а затем сгруппировать по продуктам.

Редактировать: Я обновилзапрос с $ group by code тоже.Также вы можете поиграть с запросом здесь: https://mongoplayground.net/p/2EA-Glz8Hrm

Product.aggregate([
  {
    $match: {
      _id: "5cc9441feed4c258881c99cd"
    }
  },
  {
    $lookup: {
      from: "comments",
      localField: "_id",
      foreignField: "product",
      as: "comments"
    }
  },
  {
    $unwind: "$comments"
  },
  {
    $lookup: {
      from: "users",
      localField: "comments.user",
      foreignField: "_id",
      as: "comments.user"
    }
  },
  {
    $unwind: "$comments.user"
  },
  {
    $group: {
      _id: "$_id",
      // add other fields you want to include
      comments: {
        $addToSet: "$comments"
      }
    }
  },

])
0 голосов
/ 15 мая 2019

По предложению Хамзы я внес следующие изменения в свой запрос

Product.aggregate([
      {
        $match: {
          _id: mongoose.Types.ObjectId(id)
        }
      },
      {
        $lookup: {
          from: "comments",
          localField: "_id", //field from input document
          foreignField: "product", // field from documents of the 'from' collection
          as: "comments"
        }
      },
      {
        $unwind: "$comments"
      },
      {
        $lookup: {
          from: "users",
          localField: "comments.user", //field from input document
          foreignField: "_id", // field from documents of the 'from' collection
          as: "comments.user"
        }
      },
      {
        $unwind: "$comments.user"
      },
      {
        $group: {
          _id: "$_id",
          title: { $first: "$title" }, // $first returns the first expression of the document it encounters, ex. first title
          price: { $first: "$price" },
          imageUrl: { $first: "$imageUrl" },
          description: { $first: "$description" },
          rating: { $first: "$rating" },
          comments: {
            $addToSet: "$comments" // group comments and create an array
          }
        }
      },
      {
        $project: {
          _id: 1,
          title: 1,
          price: 1,
          imageUrl: 1,
          description: 1,
          rating: 1,
          comments: {
            _id: 1,
            text: 1,
            date: 1,
            user: {
              _id: 1,
              name: 1
            }
          }
        }
      }
    ])

С этим я получил желаемый результат.

...