HatzavW
HatzavW

Reputation: 570

Mongoose $elemMatch How to query both $in and $nin

I'm using Mongoose in order to check if an element exist in my DB.

For that I'm using something like-

object.aggregate([
        {$match: {
                "data": {
                    $elemMatch: {
                        $and:[
                            {name: {$in: ["A", "B"]}},
                            {name: {$nin: ["X"]}}
                        ]
                    }
                }
            }
        }
    ])

The problem is text is array. So when I'm getting ["A" , "X"] I wish the result to be empty.

Do you have any ideas?

----------- Edit ------------

Object looks something like:

example1 = { // shouldn't find - not in $in
  _id: "123",
  data: [
      {id:"1",name:"E"},
      {id:"2",name:"R"},
      {id:"3",name:"T"}      
  ]
}

example2 = { // shouldn't find - in both $in $nin
  _id: "456",
  data: [
      {id:"4",name:"A"},
      {id:"5",name:"X"},
      {id:"6",name:"Z"}      
  ]
}

example3 = { // should find - only in $in
  _id: "789",
  data: [
      {id:"7",name:"A"},
      {id:"8",name:"L"},
      {id:"9",name:"Z"}      
  ]
}

----------- Edit 2 ------------

Thanks @Anthony For helping me find a better example to the issue.

I think this issue occurs within arrays of array, example:

Data Set

[
  {
    _id: "456",
    data: [
      {
        field: [
          {
            id: "1",
            name: "A"
          },
          {
            id: "2",
            name: "B"
          },
          {
            id: "3",
            name: "Z"
          }
        ]
      },
      {
        field: [
          {
            id: "4",
            name: "A"
          },
          {
            id: "5",
            name: "X"
          },
          {
            id: "6",
            name: "Z"
          }
        ]
      }
    ]
  }
]

My solution with element match gets 2 docs: (enter link description here)

db.collection.aggregate([
  {
    $match: {
      data: {
        $elemMatch: {
          "$and": [
            {
              "field.name": {
                "$in": [
                  "A",
                  "B"
                ]
              }
            },
            {
              "field.name": {
                "$nin": [
                  "X"
                ]
              }
            }
          ]
        }
      }
    }
  }
])

The other solution suggested returns 0 docs: (enter link description here)

db.collection.find({
  "$and": [
    {
      "data.field.name": {
        "$in": [
          "A",
          "B"
        ]
      }
    },
    {
      "data.field.name": {
        "$nin": [
          "X"
        ]
      }
    }
  ]
})

Upvotes: 2

Views: 2397

Answers (1)

Ashh
Ashh

Reputation: 46481

You can try this with simple find query

db.collection.find({
  "data": {
    "$elemMatch": {
      "$and": [
        { "field.name": { "$in": [ "A", "B" ] } },
        { "field.name": { "$nin": [ "X" ] } }
      ]
    }
  }
}, {
  "data": {
    "$elemMatch": {
      "$and": [
        { "field.name": { "$in": [ "A", "B" ] } },
        { "field.name": { "$nin": [ "X" ] } }
      ]
    }
  }
})

Try it here

Upvotes: 3

Related Questions