Home > Net >  how to do a $lookup from items in subdocument array?
how to do a $lookup from items in subdocument array?

Time:04-24

Ok , im new in this mongodb world an i have some troubles with it.

i have 3 collections , products , comments y users. products store an array of objectid from comments , an comments store the user_id.

this is the product document example.

{
  "_id": {
    "$oid": "625f1825fd0569646907dbb2"
  },
  "id": {
    "$numberInt": "1"
  },
  "title": "Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops",
  "price": {
    "$numberDouble": "109.95"
  },
  "description": "Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday",
  "category": "men's clothing",
  "image": "https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg",
  "rating": {
    "rate": {
      "$numberDouble": "3.9"
    },
    "count": {
      "$numberInt": "120"
    }
  },
  "comments": [
    {
      "id": {
        "$oid": "62607a918aaf3e14a2cd1f0e"
      }
    }
  ]
}

this is the comments example

{
  "_id": {
    "$oid": "62607a918aaf3e14a2cd1f0e"
  },
  "user_id": {
    "$oid": "625f1ae4b0e88cd486276a54"
  },
  "comment": "asdjfaslkdf",
  "product_id": {
    "$oid": "625f1825fd0569646907dbb2"
  },
  "rating": {
    "rate": {
      "$numberInt": "0"
    },
    "votes": {
      "$numberInt": "0"
    }
  }
}

And this is the user example.

{
  "_id": {
    "$oid": "625f1ae4b0e88cd486276a54"
  },
  "name": "Ursula",
  "username": "lahee",
  "create_at": {
    "$date": {
      "$numberLong": "1650399972095"
    }
  },
  "password": "$2a$10$Av3HTLljhDkDxoVEyRKGwe4M42A4HHZMWcCfThdOQHbmA3H5EGsny",
  "email": "[email protected]",
  "phone": "102394523",
  "preferences": [],
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyNWYxYWU0YjBlODhjZDQ4NjI3NmE1NCIsInVzZXJuYW1lIjoibGFoZWUiLCJpYXQiOjE2NTA0ODMzMzEwODUsImV4cCI6MTY1MDQ4MzMzNDY4NX0.UXV7I-1XBZ3T_Y0aPBPdP-gdkPMqvM6dEnZcHXg5_5g",
  "role": "user",
  "__v": {
    "$numberInt": "0"
  }
}

with this documents i want to get all product with comments and user name and email like this:

{
  "_id": {
    "$oid": "625f1825fd0569646907dbb2"
  },
  "price": 109.95,
  "description": "Your perfect pack for everyday use and walks in the forest. Stash your laptop (up to 15 inches) in the padded sleeve, your everyday",
  "comments": [
    {
      "_id": {
        "$oid": "62607a918aaf3e14a2cd1f0e"
      },
      "comment": "asdjfaslkdf",
      "user": [
        {
          "_id": {
            "$oid": "625f1ae4b0e88cd486276a54"
          },
          "name": "Ursula",
          "email": "[email protected]"
        }
      ]
    }
  ]
}

i tried with some rules and querys , the best give me the same user for all comments.

db.products.aggregate([
        {
            $lookup: {
                from: "comments",
                let: { comment_id: "$comments.id" },
                pipeline: [
                    { $match: { $expr:{ $eq:[ "$_id", "$$comment_id" ] } } },
                    {
                        $lookup: {
                            from: "users",
                            localField: "user_id",
                            foreignField: "_id",
                            as: "user"
                        }
                    },
                    
                ],
                as: "comments"
            }
        },
        {
            $project:{
                _id:1,
                name:1,
                price:1,
                description:1,
                comments:{
                    _id:1,
                    comment:1,
                    date_at:1,
                    rate:1,
                    user:{
                        _id:1,
                        name:1,
                        email:1
                    },

                },
            }
        }
    ])

anyone can help me with this problem , i want understand better the pipelines an mongodb querys .

Thanks.

CodePudding user response:

Here's one way you could get your desired output.

db.products.aggregate([
  { // may be multiple comments (or none!)
    "$unwind": {
      "path": "$comments",
      "preserveNullAndEmptyArrays": true
    }
  },
  { // two-stage lookup
    "$lookup": {
      "from": "comments",
      "localField": "comments.id",
      "foreignField": "_id",
      "pipeline": [
        { // get user info
          "$lookup": {
            "from": "users",
            "localField": "user_id",
            "foreignField": "_id",
            "pipeline": [
              {
                "$project": {
                  "name": 1,
                  "email": 1
                }
              }
            ],
            "as": "users"
          }
        },
        {
          "$project": {
            "comment": 1,
            "users": 1
          }
        }
      ],
      "as": "comments"
    }
  },
  { // only fields needed
    "$project": {
      "comments": 1,
      "description": 1,
      "price": 1
    }
  },
  { // groups all comments together
    "$group": {
      "_id": "$_id",
      "description": { "$first": "$description" },
      "price": { "$first": "$price" },
      "comments": { "$push": { "$first": "$comments" } }
    }
  }
])

Try it on mongoplayground.net.

  • Related