1

I want to find inside array of object based upon 2 conditions, in mongodb collection. Please refer the attached image for schema.

enter image description here

My query is like this:

Find inside toUsers array, where _id == given ObjectId AND user=given_user_object_id, AND visited == false

Basically I want to filter out all users with visited == false, for a given _id.

 [{
  "_id": {
    "$oid": "651548277423d019b0c251f6"
  },
  "toUsers": [
    {
      "user": {
        "$oid": "65014c6303b5bf048f627b72"
      },
      "visited": true,
      "createdAt": {
        "$date": "2023-09-28T09:32:23.352Z"
      },
      "updatedAt": {
        "$date": "2023-09-28T11:44:00.673Z"
      }
    },
    {
      "user": {
        "$oid": "650167123cc7410860126076"
      },
      "visited": false,
      "createdAt": {
        "$date": "2023-09-28T09:32:23.352Z"
      },
      "updatedAt": {
        "$date": "2023-09-28T09:32:23.352Z"
      }
    }
  ],
  "notification": {
    "message": "ccc - Skumar required approval for this workbook. This is very long text that might truncate",
    "action": {
      "workbook": "6511674ed0a5e9db5823051b",
      "actionText": "Goto Workbook"
    }
  },
  "expiryTime": {
    "$date": "2022-03-06T11:00:00.000Z"
  },
  "createdBy": {
    "$oid": "65014c6303b5bf048f627b72"
  },
  "updatedBy": "65014c6303b5bf048f627b72",
  "createdAt": {
    "$date": "2023-09-28T09:32:23.352Z"
  },
  "updatedAt": {
    "$date": "2023-09-28T11:44:00.673Z"
  }
},
{
  "_id": {
    "$oid": "6515493994822bf9866ee885"
  },
  "toUsers": [
    {
      "user": {
        "$oid": "65014c6303b5bf048f627b72"
      },
      "visited": true,
      "createdAt": {
        "$date": "2023-09-28T09:36:57.827Z"
      },
      "updatedAt": {
        "$date": "2023-09-28T11:18:59.759Z"
      }
    },
    {
      "user": {
        "$oid": "650167123cc7410860126076"
      },
      "visited": false,
      "createdAt": {
        "$date": "2023-09-28T09:36:57.828Z"
      },
      "updatedAt": {
        "$date": "2023-09-28T09:36:57.828Z"
      }
    }
  ],
  "notification": {
    "message": "zzz - SKumar required approval for this workbook. This is very long text that might truncate",
    "action": {
      "workbook": "6511674ed0a5e9db5823051b",
      "actionText": "Goto Workbook"
    }
  },
  "expiryTime": {
    "$date": "2022-03-06T11:00:00.000Z"
  },
  "createdBy": {
    "$oid": "65014c6303b5bf048f627b72"
  },
  "updatedBy": {
    "$oid": "65014c6303b5bf048f627b72"
  },
  "createdAt": {
    "$date": "2023-09-28T09:36:57.828Z"
  },
  "updatedAt": {
    "$date": "2023-09-28T11:18:59.759Z"
  }
}]
7
  • Hi, added json data now. Thanks Commented Sep 28, 2023 at 12:23
  • not entirely sure what you wanted mongoplayground.net/p/ScaSUTDOmzg Commented Sep 28, 2023 at 12:27
  • Yooooooo sir, thanks a lot. Exactly what I wanted. I only have basic knowledge of Mongo, so couldn't reach to this solution. Thanks again. Commented Sep 28, 2023 at 16:05
  • cool do u want to post as solution Commented Sep 28, 2023 at 16:13
  • sure sir. plz go ahead. Commented Sep 28, 2023 at 16:26

1 Answer 1

1
  • you can use $filter to filter the toUsers array based on your condition
  1. First filter out the main document using the _id
  2. Filter the toUsers of the filtered document

by using the $addFields you won't lose the other fields so you have freedom to $project any unwanted fields.

db.collection.aggregate([
  { $match: { "_id": ObjectId("651548277423d019b0c251f6") } },
  {
    $addFields: {
      toUsers: {
        $filter: {
          input: "$toUsers",
          cond: {
            $and: [
              { $eq: [ "$$this.user", ObjectId("650167123cc7410860126076") ] },
              { $eq: [ "$$this.visited", false ] }
            ]
          }
        }
      }
    }
  },
  { $match: { toUsers: { $ne: [] }  } } //to avoid document when toUsers empty
])

demo

  • Using an $unwind->$match-> $group strategy. I prefer the former approach since here you will lose the other fields unless you explicitly specify them in the $group using $first
db.collection.aggregate([
  { $match: { "_id": ObjectId("651548277423d019b0c251f6") } },
  { $unwind: "$toUsers" },
  { $match: { "toUsers.user": ObjectId("650167123cc7410860126076"), "toUsers.visited": false } },
  { $group: { _id: "$_id", toUsers: { $push: "$toUsers" } } }
])

demo

Sign up to request clarification or add additional context in comments.

3 Comments

there is one small issue in $filter demo, if I search for a user whose visited===true, this query still gives that document, in which toUsers array in empty. But I dont want that document in return. Please help, how can I acheive that?
Have a match stage at the end? { $match: { toUsers: { $ne: [] } } }
Got it, thanks sir.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.