mongodb-как инвертировать запрос с помощью $not?

Я хочу выбрать все документы, кроме документов с кодом, начинающимся с AAA, если имя также равно BB или CC.

Я думаю, что последний запрос ниже является явным, я, конечно, ожидал бы получить 225506-125102 документов, а не 0. Так что результат здесь определенно неожиданный.

> db.amon.find().count()
225506
> db.amon.find({code: /^AAA/, 'author.name': {'$in': ['BB', 'CC']}}).count()
125102
> db.amon.find({$not: {code: /^AAA/, 'author.name': {'$in': ['BB', 'CC']}}}).count()
0

3 ответов


какой запрос вы запускаете, который не дает правильных результатов? Какую версию MongoDB вы используете? Ваш $not запрос не является допустимым запрос в MongoDB 2.6:

> db.amon.find({ "$not" : { "code" : /^AAA/, "name" : { "$in" : ["BB", "CC"] } } })
error: {
    "$err" : "Can't canonicalize query: BadValue unknown top level operator: $not",
    "code" : 17287
}

вот пример, который делает то, что вы хотите:

> db.amon.find().pretty()
{
    "_id" : ObjectId("53ea66bdf9b63e0dd3ca1a18"),
    "code" : "AAA",
    "name" : "AA"
}
{
    "_id" : ObjectId("53ea66c1f9b63e0dd3ca1a19"),
    "code" : "AAA",
    "name" : "BB"
}
{
    "_id" : ObjectId("53ea66c3f9b63e0dd3ca1a1a"),
    "code" : "AAA",
    "name" : "CC"
}
{
    "_id" : ObjectId("53ea66d3f9b63e0dd3ca1a1b"),
    "code" : "BBB",
    "name" : "AA"
}
{
    "_id" : ObjectId("53ea66d6f9b63e0dd3ca1a1c"),
    "code" : "BBB",
    "name" : "BB"
}
{
    "_id" : ObjectId("53ea66daf9b63e0dd3ca1a1d"),
    "code" : "BBB",
    "name" : "CC"
}
> db.amon.find({ 
    "$or" : [
        { "code" : { "$not" : /^AAA/ } }, 
        { "name": { "$not" : { "$in" : ["BB", "CC"] } } } 
    ] 
})
{ "_id" : ObjectId("53ea66bdf9b63e0dd3ca1a18"), "code" : "AAA", "name" : "AA" }
{ "_id" : ObjectId("53ea66d3f9b63e0dd3ca1a1b"), "code" : "BBB", "name" : "AA" }
{ "_id" : ObjectId("53ea66d6f9b63e0dd3ca1a1c"), "code" : "BBB", "name" : "BB" }
{ "_id" : ObjectId("53ea66daf9b63e0dd3ca1a1d"), "code" : "BBB", "name" : "CC" }

простой способ записать этот запрос-использовать DeMorgan это: дополнением пересечения (и) является объединение дополнений. Поскольку вы ищете документы, которые не удовлетворяют (код AAA) и (имя является одним из BB или CC), условие они удовлетворяют не ((код AAA) и (имя является одним из BB или CC)) = (код не AAA) или (имя не BB или CC).


используйте $ne или $nin см. ссылку операторы

db.amon.find().count() 225506
db.amon.find({code: /^AAA/, 'author.name': {'$in': ['BB', 'CC']}}).count() 125102
db.amon.find({$not: {code: /^AAA/, 'author.name': {'$in': ['BB', 'CC']}}}).count() 0

could be 

db.amon.find({code: { $ne : /^AAA/}, 'author.name': {'$nin': ['BB', 'CC']}}}).count() 

and if you want this to work as index only then create a compond index on the 2 fields

db.amon.find({code: { $ne : /^AAA/}, 'author.name': {'$nin': ['BB', 'CC']}}},{code:1,_id:0}).count()

and if you want it to work on a sharded cluster
db.amon.find({code: { $ne : /^AAA/}, 'author.name': {'$nin': ['BB', 'CC']}}},{code:1,_id:0}).explain().n

просто судя по постановке задачи, я думаю, что этот запрос должен работать для вас:

db.amon.find({$and:[{code: {$not:/^AAA/}},{ 'author.name': {'$in': ['BB', 'CC']}}]}).count();