Sunag
Sunag

Reputation: 75

Unable to get result from $match with $and in pymongo

I have mongodb query which I am trying to implement with pymongo.

I have the collection dictionaries as below:

{'_id': 0,
 'name': 'aimee Zank',
 'scores': [{'score': 10.463179736705023, 'type': 'exam'},
  {'score': 11.78273309957772, 'type': 'quiz'},
  {'score': 75.8740349954354, 'type': 'homework'}]}


{'_id': 1,
 'name': 'Tomas Jude',
 'scores': [{'score': 55.9736705023, 'type': 'exam'},
  {'score': 50.78273309957772, 'type': 'quiz'},
  {'score': 45.8740349954354, 'type': 'homework'}]}

I am trying to query for students with score higher than 40 in all three types (exam, quiz and homework). For this, I am using $match with $and in the aggregate. I am unable to get any result, with $or the condition works correctly.

agg_result=Collection.aggregate([
    {"$unwind" : "$scores" },
   {"$match": {"scores.score": {"$gt":40}}},
   { 
       "$match": {
           "$and" : [
                     {"scores.type": "exam"},
                     {"scores.type":"homework"}
                     ]
                  }
    },
   
   {
       "$group": {
           "_id" : "$_id",
           "name": {"$first": "$name"},
          "scores":{"$push" : "$scores"}
       }
   },
   
  {
      "$sort": {
          "_id" : 1
      }
  }

])

With $or, the result shows as,

{'_id': 0,
     'name': 'aimee Zank',
     'scores': [{'score': 75.8740349954354, 'type': 'homework'}]}

{'_id': 1,
     'name': 'Tomas Jude',
     'scores': [{'score': 55.9736705023, 'type': 'exam'},
      {'score': 45.8740349954354, 'type': 'homework'}]}

How to work around for $and?

Upvotes: 0

Views: 71

Answers (1)

rickhg12hs
rickhg12hs

Reputation: 11932

I may have made a mountain out of a molehill, but it was the first thing that came to mind (which means there's probably a better way). You can use "$map" to cycle through the scores array where we can check the score with the type and build the pass array.

db.collection.aggregate([
  {
    // create array of pass status
    "$set": {
      "pass": {
        "$map": {
          "input": "$scores",
          "as": "score",
          "in": {
            "$switch": {
              "branches": [
                {
                  "case": { "$eq": [ "$$score.type", "exam" ] },
                  "then": { "exam": { "$gt": [ "$$score.score", 40 ] } }
                },
                {
                  "case": { "$eq": [ "$$score.type", "quiz" ] },
                  "then": { "quiz": { "$gt": [ "$$score.score", 40 ] } }
                },
                {
                  "case": { "$eq": [ "$$score.type", "homework" ] },
                  "then": { "homework": { "$gt": [ "$$score.score", 40 ] } }
                }
              ],
              "default": "$$score"
            }
          }
        }
      }
    }
  },
  {
    "$match": {
      "pass.exam": true,
      "pass.quiz": true,
      "pass.homework": true
    }
  },
  // uncomment to "$unset" "pass"
  //  {
  //    "$unset": "pass"
  //  }
])

Try it on mongoplayground.net.

Upvotes: 1

Related Questions