Search code examples
mongodbaggregation-frameworkaggregate

How to query embedded array of objects based on conditions in mongodb


I have an array of objects embedded in a document and there are multiple such documents in an collection. How to do I query those embedded array of objects with below conditions(based on the documents I have below).

  1. First get objects whose "status" is "active"(status will not be in all the objects but only few)

  2. Then get the "parent_user_id" of the above satisfied object and match it with the rest of the objects "parent_user_id" and get those objects

  3. the result of the above conditions have to set instead of the original Array (i.e: "users") of objects in the output instead of all the objects present. So if you take a look at the result am expecting there are 3 elements missing from the user array because those elements did not satisfy the above conditions. Document I have in collection(there will be multiple document as such)

    {
        "_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
        "name" : "A",
        "description" : null,
        "users" : [
            {
                "id" : "63a8808c52f40e1d48a3d1da",
                "owner" : "John Doe",
                "purchase_date" : "2022-12-25,
                "status" : "active",
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
                "recent_items": ["tomato",onion]
            },
            {
                "id" : "63a880a552f40e1d48a3d1dc",
                "owner" : "John Doe 1",
                "purchase_date" : "2022-12-25,
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
                "recent_items": ["onion"]
            },
            {
                "id" : "63a880f752f40e1d48assddd"
                "owner" : "John Doe 2",
                "purchase_date" : "2022-12-25,
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
            },
            {
                "id" : "63a880f752f40e1d48a3d207"
                "owner" : "John Doe 11",
                "dt" : "2022-12-25,
                "status" : "inactive",
                "parent_user_id" : "63a880f752f40e1d48a3d207",
            },
            {
                "id" : "63a880f752f40e1d48agfmmb"
                "owner" : "John Doe 112",
                "dt" : "2022-12-25,
                "status" : "active",
                "parent_user_id" : "63a880f752f40e1d48agfmmb",
                "recent_items": ["tomato"]
            }
            {
                "id" : "63a880f752f40e1d48agggg"
                "owner" : "John SS",
                "dt" : "2022-12-25,
                "status" : "inactive",
                "parent_user_id" : "63a880f752f40e1d48agggg",
            }
            {
                "id" : "63a880f752f40e1d487777"
                "owner" : "John SS",
                "dt" : "2022-12-25,
                "parent_user_id" : "63a880f752f40e1d48agggg",
            }
        ]
    }
    

Result am expecting

{
  "_id" : ObjectId("63a8808652f40e1d48a3d1d7"),
  "name" : "A",
  "description" : null,
        "users" : [
            {
                "id" : "63a8808c52f40e1d48a3d1da",
                "owner" : "John Doe",
                "purchase_date" : "2022-12-25,
                "status" : "active",
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
                "recent_items": ["tomato",onion]
            },
            {
                "id" : "63a880a552f40e1d48a3d1dc",
                "owner" : "John Doe 1",
                "purchase_date" : "2022-12-25,
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
            },
            {
                "id" : "63a880f752f40e1d48assddd"
                "owner" : "John Doe 2",
                "purchase_date" : "2022-12-25,
                "parent_user_id" : "63a8808c52f40e1d48a3d1da",
            },
            {
                "id" : "63a880f752f40e1d48agfmmb"
                "owner" : "John Doe 112",
                "dt" : "2022-12-25,
                "status" : "active",
                "parent_user_id" : "63a880f752f40e1d48agfmmb",
                "recent_items": ["tomato"]
            }
        ]
    }

Solution

  • i would use some $filter stages as follows :

    db.collection.aggregate([
      {
        $addFields: {
          users_matched: {
            $filter: {
              input: "$users",
              as: "user",
              cond: {
                $eq: [
                  "active",
                  "$$user.status"
                ],
                
              },
              
            },
            
          },
          
        },
        
      },
      {
        $set: {
          users: {
            $filter: {
              input: "$users",
              as: "user",
              cond: {
                $in: [
                  "$$user.parent_user_id",
                  "$users_matched.id"
                ],
                
              },
              
            },
            
          },
          
        },
        
      },
      {
        $unset: "users_matched"
      }
    ])
    

    You can check for yourself on mongoplayground https://mongoplayground.net/p/SrpsWb4v21x

    EDIT TO ANSWER THE SECOND QUESTION:

    You could fix your tomato problem as follows :

    db.collection.aggregate([
      {
        $addFields: {
          active_users: {
            $filter: {
              input: "$users",
              as: "user",
              cond: {
                $eq: [
                  "active",
                  "$$user.status"
                ],
                
              },
              
            },
            
          },
          tomato_users: {
            $filter: {
              input: "$users",
              as: "user",
              cond: {
                $in: [
                  "tomato",
                  {
                    "$ifNull": [
                      "$$user.recent_items",
                      []
                    ]
                  }
                ],
                
              },
              
            },
            
          }
        },
        
      },
      {
        $set: {
          users: {
            $filter: {
              input: "$users",
              as: "user",
              cond: {
                $and: [
                  {
                    $in: [
                      "$$user.parent_user_id",
                      "$active_users.id"
                    ],
                    
                  },
                  {
                    $in: [
                      "$$user.parent_user_id",
                      "$tomato_users.parent_user_id"
                    ],
                    
                  }
                ]
              },
              
            },
            
          },
          
        },
        
      },
      {
        $unset: [
          "active_users",
          "tomato_users"
        ]
      }
    ])
    

    See on mongoplayground https://mongoplayground.net/p/mb21UT475yt