skip to Main Content

A sample collection

[
  {
    "_id":"id1",
    "usersArray":[
      {
        "name":"user1Name",
        "type":1
      },
      {
        "name":"user2Name",
        "type":1
      },
      {
        "name":"user3Name",
        "type":2
      },
    ]
  },
  {
    "_id":"id2",
    "usersArray":[
      {
        "name":"user4Name",
        "type":1
      },
      {
        "name":"user5Name",
        "type":3
      },
      {
        "name":"user6Name",
        "type":2
      },
    ]
  },
  {
    "_id":"id3",
    "usersArray":[
      {
        "name":"user7Name",
        "type":1
      },
      {
        "name":"user8Name",
        "type":1
      },
      {
        "name":"user9Name",
        "type":2
      },
    ]
  },
]

What I need is a filter that will return the documents with _id id1 and id3 since they have more than 1 objects in usersArray which have key-value pairs "type": 1. It would be great if you could resolve this with just the filter.

2

Answers


    1. $expr – Allow using aggregation operator.

      1.1. $gt – Filter the document with the result of 1.1.1 greater than 1.

      1.1.1. $size – Get the size of the result 1.1.1.1.

      1.1.1.1. $filter – Filter the document(s) with type: 1 in usersArray.

    db.collection.find({
      $expr: {
        $gt: [
          {
            $size: {
              $filter: {
                input: "$usersArray",
                cond: {
                  $eq: [
                    "$$this.type",
                    1
                  ]
                }
              }
            }
          },
          1
        ]
      }
    })
    

    Sample Mongo Playground


    In case usersArray is possibly null or not array, then you need to check the usersArray is an array, else assign an empty array via $cond and $isArray.

    db.collection.find({
      $expr: {
        $gt: [
          {
            $size: {
              $filter: {
                input: {
                  $cond: {
                    if: {
                      $isArray: "$usersArray"
                    },
                    then: "$usersArray",
                    else: []
                  }
                },
                cond: {
                  $eq: [
                    "$$this.type",
                    1
                  ]
                }
              }
            }
          },
          1
        ]
      }
    })
    

    Sample Mongo Playground (With check array)

    Login or Signup to reply.
  1. Query

    • make it set($union with empty), get the $size
    • get the original $size
    • if set size < original size => it contained duplicated type

    *this is a way to do it not for type:1 duplicate only, this keeps documents that dont have duplicate same types, i am not sure what you need. (for example if type:2 is duplicated document wont pass the filter also)

    Playmongo

    aggregate(
    [{"$match": 
       {"$expr": 
         {"$lt": 
           [{"$size": {"$setUnion": ["$usersArray.type", []]}},
            {"$size": "$usersArray.type"}]}}}])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search