mongodb - 如何用$ not反转查询?

Piv*_*ert 8 mongodb

如果名称也等于BB或CC,我想选择所有文件,但代码以AAA开头的文件除外.

我认为下面的最后一个查询是明确的,我当然希望得到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
Run Code Online (Sandbox Code Playgroud)

nob*_*bar 9

问题

$not 不能用于简单地反转现有表达式。

var originalSelection = {code: /^AAA/, 'author.name': {'$in': ['BB', 'CC']}}
var invalidSelection = {$not:originalSelection}
Run Code Online (Sandbox Code Playgroud)

“未知的顶级运算符:$not”


解决方案

简单的解决方案是使用$nor运算符,将表达式作为单项数组传递。

var inverseSelection = {$nor:[originalSelection]}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为单个操作数的 NOR 等效于 NOT。


wdb*_*ley 7

你正在运行的查询是什么,没有给出正确的结果?您使用的是哪个版本的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
}
Run Code Online (Sandbox Code Playgroud)

这是一个做你想要的例子:

> 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" }
Run Code Online (Sandbox Code Playgroud)

写下这个查询的简单方法是使用DeMorgan定律:交集(和)的补充是补语的并集.由于您正在搜索不满足的文档(代码为AAA)和(名称是BB或CC之一),因此它们满足的条件不是((代码是AAA)和(名称是BB或CC之一)) =(代码不是AAA)或(名称不是BB或CC).

  • 对答案的一个小改进是使用 $nin 运算符而不是 $not,然后是 $in。 (2认同)