skip to Main Content

I’m trying to make a $and clause within a $match clause. This $and clause should have a full complete comparison against the string I’m providing. I’d like to make sure that the comparisong with attributes.value should be exact the string I’m passing. With the following expression:

db.getCollection('cards').aggregate([{
    "$match" : {
        "$and" : [
            { "attributes.key" : "setCode", "attributes.value" : "qc" },
            { "attributes.key" : "code", "attributes.value" : "potions" }
        ]
    }
}

As you can see, I get results that match with the code like potion, potions, cauldron potion. I’m also getting results where other attributes with different keys, have the word potions within.

Some sample data that is returned with the query above:

[
  {
    "_id": {"$oid": "66ab6eec2982eff57de4420f"},
    "attributes": {
      "name": "Gold Cauldron",
      "code": "gold-cauldron",
      "text": "To play this card, return 2 of your Potions Lessons from play to your hand.",
      "illustrator": "Bob Petillo",
      "orientation": "horizontal",
      "set": "Quidditch Cup",
      "setCode": "qc",
      "type": "Item",
      "typeCode": "item",
      "rarity": "Foil Premium",
      "rarityCode": "foil-premium",
      "lessonType": "Potions",
      "lessonTypeCode": "potions",
      "lessonCost": "9",
      "actionCost": "1",
      "cardNumber": "7",
      "providesLesson": "Potions",
      "subType": ["Cauldron"]
    },
    "language": "en"
  },
  {
    "_id": {"$oid": "66ab6eec2982eff57de44247"},
    "attributes": {
      "name": "Mopsus Potion",
      "code": "mopsus-potion",
      "text": "Do 3 damage to yout opponent or to a Creature of your choice.",
      "illustrator": "Greg Hildebrandt",
      "orientation": "vertical",
      "set": "Quidditch Cup",
      "setCode": "qc",
      "type": "Spell",
      "typeCode": "spell",
      "rarity": "Common",
      "rarityCode": "common",
      "lessonType": "Potions",
      "lessonTypeCode": "potions",
      "lessonCost": "8",
      "actionCost": "1",
      "cardNumber": "63",
      "subType": ""
    },
    "language": "en"
  },
  {
    "_id": {"$oid": "66ab6eec2982eff57de44256"},
    "attributes": {
      "name": "Potions",
      "code": "potions",
      "text": "Provides 1 Potions lesson.",
      "illustrator": "Shanth Enjeti, Melissa Ferreira",
      "orientation": "horizontal",
      "set": "Quidditch Cup",
      "setCode": "qc",
      "type": "Lesson",
      "typeCode": "lesson",
      "rarity": "Common",
      "rarityCode": "common",
      "lessonType": "Potions",
      "lessonTypeCode": "potions",
      "actionCost": "1",
      "cardNumber": "78",
      "providesLesson": "Potions",
      "subType": ""
    },
    "language": "en"
  }
]

So my $match clause is not respecting the attributes.key with values setCode and code, because it’s comparing with other attributes.

How can I make sure that the above $match condition matches only the given keys and given values?

Thank you all!

2

Answers


  1. Chosen as BEST ANSWER

    It is possible to achieve the results I want by following @aneroid's suggestion with $elemMatch:

    db.getCollection('cards').aggregate([{
      "$match": {
        "attributes": {
          $elemMatch: {
            key: "setCode",
            value: "qc"
          }
        }
      }
    }, {
      "$match": {
        "attributes": {
          $elemMatch: {
            key: "code",
            value: "potions"
          }
        }
      }
    }]);
    

    If anyone knows a better way for achieving the same result with a simpler query, let me know!


  2. Since attributes is an object and not an array of key-value fields, you don’t need to do attr.key & attr.value. (And you also wouldn’t need $elemMatch for your example data.)

    Use the keys & values directly in the match:

    db.getCollection('cards').aggregate([
      {
        $match: {
          "attributes.setCode": "qc",
          "attributes.code": "potions"
        }
      }
    ])
    

    Mongo Playground

    And unless you need an aggregation pipeline for some other steps, this can be used directly in a find query:

    db.cards.find({
      "attributes.setCode": "qc",
      "attributes.code": "potions"
    })
    

    Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search