skip to Main Content

I’ve been having trouble trying to query for a deeply nested subdocument while using Mongoose.
My DB structure is like this:

{
    "_id": "662aa6ccae109745e30dc664",
    "username": "username",
    "email": "[email protected]",
    "lists": [
        {
            "_id": "662aa6dbae109745e30dc66a"
            "name": "list",
            "content": [
                {
                    "_id": "662aa6eeae109745e30dc670"
                    "name": "product",
                    "quantity": 30,
                    "brands": [],
                }
            ],
        },
    ],
}

All I want is to query for the product _id ("_id": "662aa6eeae109745e30dc670" for example) and get the list and user _id("_id": "662aa6dbae109745e30dc66a" and "_id": "662aa6ccae109745e30dc664" respectively, on this example).

I’ve tried queryin for:

const user = await findOne({ 'lists.content._id': '662aa6eeae109745e30dc670' })

But this returns the whole user object. How can I query so it’s return only the product object (since I can use the ‘child.parent()’ method to get the listId)

2

Answers


  1. Use an aggregation pipeline so you can $unwind each array lists & then lists.content. Then match on the criteria for lists.content._id and project the fields you want.

    db.collection.aggregate([
      { $unwind: "$lists" },
      { $unwind: "$lists.content" },
      {
        $match: {
          "lists.content._id": "662aa6eeae109745e30dc670"
        }
      },
      {
        $project: {
          // _id will be included anyway
          list_id: "$lists._id",
          content_id: "$lists.content._id"
        }
      },
      // limit to just one doc if that's a requirement; NOT recommended
      { $limit: 1 }
    ])
    

    Result:

    [
      {
        "_id": "662aa6ccae109745e30dc664",
        "content_id": "662aa6eeae109745e30dc670",
        "list_id": "662aa6dbae109745e30dc66a"
      }
    ]
    

    Mongo Playground


    If you want the _id fields as they were nested in the original doc, use this $project stage instead:

      {
        $project: {
          "lists._id": 1,
          "lists.content._id": 1
        }
      }
    

    Result:

    [
      {
        "_id": "662aa6ccae109745e30dc664",
        "lists": {
          "_id": "662aa6dbae109745e30dc66a",
          "content": {
            "_id": "662aa6eeae109745e30dc670"
          }
        }
      }
    ]
    
    Login or Signup to reply.
  2. db.collection.aggregate([
      {
        $unwind: "$lists" 
      },
      {
        $unwind: "$lists.content"
      },
      {
        $match: {
          "lists.content._id": ObjectId("662aa6eeae109745e30dc670")
        }
      },
      {
        $project: {
          _id: 0,
          user_id: "$_id",
          list_id: "$lists._id",
          product_id: "$lists.content._id" 
        }
      }
    ])
    

    Result:

    [
      {
        user_id: ObjectId("662aa6ccae109745e30dc664"),
        list_id: ObjectId("662aa6dbae109745e30dc66a"),
        product_id: ObjectId("662aa6eeae109745e30dc670")
      }
    ]
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search