Home > Enterprise >  How to check if 2 elements inside an array of objects have the same value, in mongoDB?
How to check if 2 elements inside an array of objects have the same value, in mongoDB?

Time:08-11

My users collection data looks like this inside mongoDB:

_id: ObjectId,
sports: [
  {
    name: 'cricket',
    history: [
      {
        from: 10,
        to: 30
      },
      {
        from: 30,
        to: 30
      }
    ]
  },
  // ... other sports as well
]

What I'm trying to query for are all the users that have inside sports.history an matching element that satisfies this condition: from === to. (Users can have multiple sports each with it's own history). I'm trying to achieve this inside the query, not bring users inside my express app and filter them afterwards.

Any help is much appreciated. Thanks!

CodePudding user response:

Using $expr operator, you can go about this using various array operators to query the collection. Consider first flattening the 2D array '$sports.history' with $reduce:

 {
    $reduce: {
        input: "$sports.history",
        initialValue: [],
        in: { $concatArrays: [ "$$value", "$$this" ] }
    }
}

and filtering the reduced array on the given condition with $filter

{ $filter: {
    input: {
        $reduce: {
            input: "$sports.history",
            initialValue: [],
            in: { $concatArrays: [ "$$value", "$$this" ]
            }
        }
    },
    cond: {
        $eq: ['$$this.from', '$$this.to']
    }
} }

Check the length of the array resulting from the above expression using $size:

{ $size: { 
    { $filter: {
        input: '$sports.history',
        cond: {
            $eq: ['$$this.from', '$$this.to']
        }
    } }
} }

If length of filtered array is greater than zero, then the user exists:

{ $gt: [
    { $size: { 
        { $filter: {
            input: '$sports.history',
            cond: {
                $eq: ['$$this.from', '$$this.to']
            }
        } }
    } },
    0
] }

Overall your final query should look like this:

db.users.find({
    $expr: {
        $gt: [
            { $size: {
                $filter: {
                    input: '$sports.history',
                    cond: {
                        $eq: ['$$this.from', '$$this.to']
                    }
                }
            } },
            0
        ]
    }
})

Mongo Playground

  • Related