0

I want to filter the documents based on importkeyid and MissingPersonIds.PhotoId array field. The filter on MissingPersonIds.PhotoId should work like 'sql - like' operator.

Schema:

[{
  "_id": {
    "$oid": "61ada7da9a30fd8471869bbc"
  },
  "ImportKeyId": 5843,
  "Name" : "AV"
  "MissingPersonIds": [
    {
      "PhotoId": "2 - Copy.jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "2 - Copy - Copy.jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "2 - Copy - Copy (2).jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "202020 - Copy (2).jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "202020 - Copy - Copy.jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "202020 - Copy - Copy (2).jpg",
      "Description": "Account ID not found"
    }
  ]
},
{
  "_id": {
    "$oid": "619cd7d2181999c9a4da790a"
  },
  "ImportKeyId": 5753,
  "Name" : 'av1'
  "MissingPersonIds": [
    {
      "PhotoId": "94578.jpg",
      "Description": "Photo id is not found"
    },
    {
      "PhotoId": "371426759.jpg",
      "Description": "Photo id is not found"
    }
  ]
}
.
.
.
]

Based on following conditions: enter image description here

Filter: { "ImportKeyId" : 5843 }

Projection: { MissingPersonIds : { $slice:[0,5] }, "MissingPersonIds": { $elemMatch: { PhotoId : { $regex: /202020 /i } } } }

I was expecting below output but $elemMatch returns only one matched record

[{
  "_id": {
    "$oid": "61ada7da9a30fd8471869bbc"
  },
  "ImportKeyId": 5843,
  "Name" : "AV"
  "MissingPersonIds": [  
    {
      "PhotoId": "202020 - Copy (2).jpg",
      "Description": "Account ID not found"
    },
    {
      "PhotoId": "202020 - Copy - Copy.jpg",
      "Description": "Account ID not found"
    }
  ]
}]

What should I used instead of $elemMatch ?

Abhishek Vyas
  • 599
  • 1
  • 9
  • 24

1 Answers1

1

Maybe something like this

db.collection.aggregate([
  {
    "$match": {
      "ImportKeyId": 5843
   }
  },
 {
"$project": {
  "_id": 1,
  "ImportKeyId": 1,
  MissingPersonIds: {
    $filter: {
      input: "$MissingPersonIds",
      as: "item",
      cond: {
        $gt: [
          {
            $indexOfCP: [
              {
                $toLower: "$$item.PhotoId"
              },
              "202020 "
            ]
          },
          -1
        ]
      }
    }
  }
  }
  }
 ])

Output:

[
  {
    "_id": ObjectId("61ada7da9a30fd8471869bbc")
    "ImportKeyId": 5843,
    "MissingPersonIds": [
  {
    "Description": "Account ID not found",
    "PhotoId": "202020 - Copy (2).jpg"
  },
  {
    "Description": "Account ID not found",
    "PhotoId": "202020 - Copy - Copy.jpg"
  },
  {
    "Description": "Account ID not found",
    "PhotoId": "202020 - Copy - Copy (2).jpg"
  }
  ],
 
  }
]

explained:

  1. In the match stage you filter only documents with the ImportKeyId: 5843
  2. With the project stage you fiter _id & ImportKeyId , and you add new field MissingPersonIds that will filter the elements in the array containing only strings like in SQL having "%202020 %" inside
R2D2
  • 9,410
  • 2
  • 12
  • 28
  • Being new to compass. How do I use the query in Compass? – Abhishek Vyas Dec 06 '21 at 14:22
  • 1
    you can copy and paste to compass , see example here: https://docs.mongodb.com/compass/current/aggregation-pipeline-builder/ – R2D2 Dec 06 '21 at 14:28
  • Its working. Where should i put { MissingPersonIds : { $slice:[0,5] } ? I am trying to apply pagination on the array field – Abhishek Vyas Dec 06 '21 at 14:36
  • 1
    You can add pagination by $slice as second project stage after the filtering : https://mongoplayground.net/p/8Sk20tTYKHs – R2D2 Dec 06 '21 at 14:53