How to combine $elemMatch with $nin or $not in a MongoDB query?

丶灬走出姿态 提交于 2019-12-11 15:02:22

问题


I want to find all results where the array fieldB does not have values (val1 and val2) in fieldC objects.

I have tried:

db.SalesToImport
  .find(
    {
      fieldA: {$exists:true},
      ,fieldB: {$not: {$elemMatch: {fieldC: 'val1'}}}
      ,fieldB: {$not: {$elemMatch: {fieldC: 'val2'}}}
    }
  );

And I have tried:

db.SalesToImport
  .find(
    {
      fieldA: {$exists:true},
      ,fieldB: {$not: {$elemMatch: {fieldC: 'val1', fieldC: 'val2'}}}
    }
  );

They both yield the same results and while they remove some documents, there are still docs with val1 and val2 in them, which tells me that I made an incorrect query.

A document's structure contains fields like so:

{
  fieldA: value,
  fieldB: [
    {fieldC:value1, fieldD:value3, fieldE:value5},
    {fieldC:value2, fieldD:value4, fieldE:value6}
  ]
}

How should I combine $elemMatch with $nin or $not in a MongoDB query to get the desired effect?

Update # 1

Based on the suggestions I ran the following realistic but sanitized query:

db.SalesToImport
  .find(
    {
      calculatedTaxRate: {$exists:true}, unidentifiedProducts: {$exists:false}, unidentifiedCustomer: {$exists:false},
      register_sale_payments: {
        $elemMatch: {
          retailer_payment_type_id : {
            $nin: [
              '0af7b240-ab24-11e7-eddc-9fff6de134e9'
              ,'0af7b240-ab24-11e7-eddc-9fff69293826'
            ]
          }, 
        }
      }
    },
    {_id:0,status:0,customer_id:0,register_id:0}
  )
  .sort({"calculatedTaxRate":1});

But the response still had the unwanted results in fieldB.fieldC or register_sale_payments.retailer_payment_type_id, so this wasn't what I was looking for or I made a mistake in using it.

Update # 2

Based on the suggestions I ran the following realistic but sanitized query:

db.SalesToImport
  .find(
    {
      calculatedTaxRate: {$exists:true}, unidentifiedProducts: {$exists:false}, unidentifiedCustomer: {$exists:false},
      'register_sale_payments.retailer_payment_type_id': {
        $nin: [
          '0af7b240-ab24-11e7-eddc-9fff6de134e9'
          ,'0af7b240-ab24-11e7-eddc-9fff69293826'
        ]
      }
    },
    {_id:0,status:0,customer_id:0,register_id:0}
  )
  .sort({"calculatedTaxRate":1});

and it worked!


回答1:


While you are interested just one field of fieldB, you don't need to use $elemmatch.

db.SalesToImport.find(
{
  "fieldA": {$exists:true},
  "fieldB.fieldC": { $nin: ["val1", "va2"] }
}
);

If you have a fieldD in fieldB and for example, you don't want fieldD have values val3, val4 too :

db.SalesToImport.find(
{
  "fieldA": { $exists: true },
  "fieldB.fieldC": { $nin: ["val1", "va2"] },
  "fieldB.fieldD": { $nin: ["val3", "va4"] }
}
);

Above query exclude documents for fieldC, fieldD pairs like that too: (val5, val3), because we are querying fieldC and fieldD seperately.

If you want to query for fieldBnot have value pairs for fieldC and fieldD (val1, val3), (val1, val4), (val2, val3), (val2, val4) :

db.SalesToImport.find(
{
  "fieldA": { $exists: true },
  "fieldB": { $elemmatch: {
    "fieldC" : { $nin: ["val1", "val2"] }, 
    "fieldD": { $nin: ["val3", "val4"] } } 
   }
}
);

Above query does not exclude filedC, fieldD pairs like: (val5, val3)



来源:https://stackoverflow.com/questions/46375888/how-to-combine-elemmatch-with-nin-or-not-in-a-mongodb-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!