【问题标题】:MongoDB using NOT and AND togetherMongoDB 一起使用 NOT 和 AND
【发布时间】:2014-07-28 09:10:26
【问题描述】:

我试图用 MongoDB 否定 $and 子句,我收到了 MongoError: invalid operator: $and 消息。基本上我想要达到的目标如下:

query = { $not: { $and: [{institution_type:'A'}, {type:'C'}] } }

这可以在 mongo 查询中表达吗?

这是一个示例集合:

{ "institution_type" : "A", "type" : "C" }
{ "institution_type" : "A", "type" : "D" }
{ "institution_type" : "B", "type" : "C" }
{ "institution_type" : "B", "type" : "D" }

我想要返回的是以下内容:

{ "institution_type" : "A", "type" : "D" }
{ "institution_type" : "B", "type" : "C" }
{ "institution_type" : "B", "type" : "D" }

【问题讨论】:

标签: mongodb mongoose


【解决方案1】:

你正在寻找NOT (A AND C),相当于NOT A OR NOT C

db.collection.find({
  "$or": [
    {"institution_type": {"$ne": "A"}},
    {"type": {"$ne": "C"}}
  ]
})

MongoDB 还有一个$nor 逻辑运算符,它“对一个或多个查询表达式的数组执行逻辑 NOR 运算,并选择数组中所有查询表达式都失败的文档”,因此等效查询将是:

db.collection.find({
  "$nor": [
    {"institution_type": "A"},
    {"type": "C"}
  ]
})

接受的答案建议使用 $where 运算符,但这在此处是不必要的,并且会影响性​​能。

【讨论】:

  • 您的第二个示例不是使用$nor 运算符查询NOT A AND NOT C,而不是NOT (A AND C)
  • 这是错误的。您可以使用以下方法进行测试: db.institutionTest.insert({ "institution_type" : "A", "type" : "C" }); db.institutionTest.insert({ "institution_type" : "A", "type" : "D" }); db.institutionTest.insert({ "institution_type" : "B", "type" : "C" }); db.institutionTest.insert({ "institution_type" : "B", "type" : "D" }); db.institutionTest.find({ "$or": [ {"institution_type": {"$ne": "A"}}, {"type": {"$ne": "C"}} ] }) 分贝.institutionTest.find({ "$nor": [ {"institution_type": "A"}, {"type": "C"} ] }) 只返回 1 个文档而不是请求的 3 个
  • $nor 对一个或多个查询表达式的数组执行逻辑 NOR 运算,并选择数组中所有查询表达式都失败的文档。 => $nor 等价于$and: [ { $not: A }, { $not: B } ],而不是$or: [ { $not: A }, { $not: B } ]
  • 不过,我正在寻找顶级$not,它实际上是$nor: [{[k]: {[op]: v}}] 等价于{[k]: {$not: {[op]: v}}}。所以,我赞成。
  • { $not: { $and: [A, B] } } 不等于@Kesarion 提到的{ $nor: [A, B] }
【解决方案2】:

不是我能看到的标准否定,您需要使用 JavaScript 的 $where 运算符样式查询:

db.collection.find(function(){ 
    return !( this.institution_type == "A" && this.type == "C" ) 
})

扫描整个集合并不是最好的,但您的逻辑中的否定需要这样做,因为您需要测试这两个值。

或者本质上等价的聚合操作:

db.collection.aggregate([
    { "$project": {
        "institution_type": 1,
        "type": 1,
        "notmatched": {
            "$not": {
                "$and": [
                    { "eq": [ "$institution_type", "A" ] },
                    { "eq": [ "$type", "C" ] }
                ]
            }
        }
    }},
    { "$match": { 
        "notmatched": true
    }}
])

通过在内部包含否定,才意识到这也是一种有效的形式:

db.collection.find({
    "$or": [
        { "institution_type": { "$ne": "A" } }, 
        { "type": { "$ne": "C" }},
    ]
})

这基本上否定了同一文档中“A”和“C”的组合,就像其他逻辑对包装“非”条件所做的那样。


原件

在 MongoDB 查询中,$and 实际上是隐式的,因为这是查询中术语的默认比较。只有在同一字段上查找多个条件时,才需要使用$and

但是你的查询是一个简单的不等式匹配:

db.collection.find({
    "institution_type": { "$ne": "bank" },
    "type": { "$ne": "account_type" }
})

因此,您使用 $ne 运算符从匹配项中否定您的条款,如前所述,$and 是隐含的,因此两个条件都必须适用。

所以用样本数据:

{ "institution_type" : "bank", "type" : "account_type" }
{ "institution_type" : "school", "type" : "account_type" }
{ "institution_type" : "school", "type" : "account" }

查询只返回不满足两个条件的行:

{ "institution_type" : "school", "type" : "account" }

您的评论说您在使用“AND”时未在查询中指定“OR”,因此您可能期望“OR”是隐含的,这与我告诉您的相反是案例。

需要明确应用$or 条件:

db.collection.find({
    "$or": [
        { "inititution_type": { "$ne": "bank" } },
        { "type": { "$ne": "account_type" } }
    ]
})

这实际上是双重否定,会返回所有结果。

也许你的意思是$nor

db.data.find({
    "$nor": [
        { "inititution_type": "bank" },
        { "type": "account_type"  }
    ]
})

但实际上这和我给你的第一个问题在逻辑上是一样的。

【讨论】:

  • 嗯,这似乎不对。我原来的查询是NOT (A AND B),应该翻译成(NOT A) OR (NOT B)。你给我的查询是(NOT A) AND (NOT B)
  • @Stankalank 不知道为什么您认为在您的问题$or 的语法中隐含了 OR 条件,正如我另外展示的那样,条件必须是明确的。所以除非你要求$or,否则比较实际上是$and
  • 好的,所以我的原始查询包含(A AND B) 子句,我们都同意。我们不同意的是当你否定它时会发生什么。您声称NOT (A AND B) 等同于(NOT A) AND (NOT B),而我声称它等同于(NOT A) OR (NOT B)。德摩根的法律似乎同意我的观点oxforddictionaries.com/us/definition/american_english/…
  • 您的最后两个查询是等价且正确的。
  • @Stankalank 我只是在帮助您获得正确的查询结果。你尝试了一些东西,它不起作用,你问一个问题,有人回答。也许您应该在问题中定义一些数据并显示您期望达到的结果。如果这与显示的示例有任何不同。如果您希望得到帮助,那么与人争论可能不是正确的选择。
【解决方案3】:

我有同样的问题,但没有解决。

我的收藏有这个项目(共 17 个):

{ 
    "_id" : ObjectId("5d9d09dff9399554b35f4fc8"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "createdAt" : ISODate("2019-10-08T22:12:47.872+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:12:47.872+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d09dff9399553df5f4fc9"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "createdAt" : ISODate("2019-10-08T22:12:47.883+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:13:10.129+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d0a00f93995da635f4fca"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "vacuo", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "createdAt" : ISODate("2019-10-08T22:13:20.310+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:13:20.310+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d0a44de4e534ba8a1eaf6"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "nao-sugerir", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d833a2a7aebc4af5ba378ca")
    }, 
    "createdAt" : ISODate("2019-10-08T22:14:28.445+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:14:28.445+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d0a48de4e534ba8a1eaf7"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "nao-sugerir", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82c2e07aebc4305da378b1")
    }, 
    "createdAt" : ISODate("2019-10-08T22:14:32.189+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:14:32.189+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d0b28de4e534ba8a1eaf8"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82de827aebc42767a378c6")
    }, 
    "createdAt" : ISODate("2019-10-08T22:18:16.235+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:18:16.235+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d0b28de4e534ba8a1eaf9"), 
    "status" : {
        "codigo" : "2", 
        "msg" : "Solicitação pendente"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82de827aebc42767a378c6")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "createdAt" : ISODate("2019-10-08T22:18:16.268+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:18:16.268+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d10eede4e534ba8a1eb0d"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82755c7aebc49efca378aa")
    }, 
    "createdAt" : ISODate("2019-10-08T22:42:54.790+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:42:54.790+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9d10eede4e534ba8a1eb0e"), 
    "status" : {
        "codigo" : "2", 
        "msg" : "Solicitação pendente"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82755c7aebc49efca378aa")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
    }, 
    "createdAt" : ISODate("2019-10-08T22:42:54.822+0000"), 
    "updatedAt" : ISODate("2019-10-08T22:42:54.822+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dad94f939952d305f4fcc"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82d8fa7aebc42be1a378c2")
    }, 
    "createdAt" : ISODate("2019-10-09T09:51:16.984+0000"), 
    "updatedAt" : ISODate("2019-10-09T09:51:16.984+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dad94f939957a905f4fcd"), 
    "status" : {
        "codigo" : "2", 
        "msg" : "Solicitação pendente"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82d8fa7aebc42be1a378c2")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "createdAt" : ISODate("2019-10-09T09:51:16.998+0000"), 
    "updatedAt" : ISODate("2019-10-09T09:51:16.998+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dad96f939956a345f4fce"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "vacuo", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d82d8fa7aebc42be1a378c2")
    }, 
    "createdAt" : ISODate("2019-10-09T09:51:18.587+0000"), 
    "updatedAt" : ISODate("2019-10-09T09:51:18.587+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dce0cf939958be25f4fcf"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d8354497aebc439a7a378d0")
    }, 
    "createdAt" : ISODate("2019-10-09T12:09:48.619+0000"), 
    "updatedAt" : ISODate("2019-10-09T12:09:48.619+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dce0cf939958c4b5f4fd0"), 
    "status" : {
        "codigo" : "2", 
        "msg" : "Solicitação pendente"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d8354497aebc439a7a378d0")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "createdAt" : ISODate("2019-10-09T12:09:48.635+0000"), 
    "updatedAt" : ISODate("2019-10-09T12:09:48.635+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dce10f9399590a65f4fd1"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d685f790215c983e4fd097e")
    }, 
    "createdAt" : ISODate("2019-10-09T12:09:52.994+0000"), 
    "updatedAt" : ISODate("2019-10-09T12:09:52.994+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9dce11f9399564715f4fd2"), 
    "status" : {
        "codigo" : "2", 
        "msg" : "Solicitação pendente"
    }, 
    "extra" : [

    ], 
    "tipo" : "amizade", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d685f790215c983e4fd097e")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "createdAt" : ISODate("2019-10-09T12:09:53.006+0000"), 
    "updatedAt" : ISODate("2019-10-09T12:09:53.006+0000"), 
    "__v" : NumberInt(0)
}
// ----------------------------------------------
{ 
    "_id" : ObjectId("5d9e4afbde4e534ba8a1eb0f"), 
    "status" : {
        "codigo" : "1", 
        "msg" : "Ativo"
    }, 
    "extra" : [

    ], 
    "tipo" : "nao-sugerir", 
    "vinculo" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d69a8eb0215c92942fd0983")
    }, 
    "vinculado" : {
        "colecao" : "atletas", 
        "objeto" : ObjectId("5d80f31e7aebc412dea3789a")
    }, 
    "createdAt" : ISODate("2019-10-09T21:02:51.026+0000"), 
    "updatedAt" : ISODate("2019-10-09T21:02:51.026+0000"), 
    "__v" : NumberInt(0)
}

在此查询中,返回正确的(4 个元素):

db.getCollection("vinculos").aggregate(
    [
        { 
            "$match" : {
                "status.codigo" : "1", 
                "tipo" : {
                    "$in" : [
                        "amizade", 
                        "nao-sugerir"
                    ]
                }, 
                "vinculo.objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
            }
        }
    ]
)

但我需要一个反义词:

第一次尝试(无结果)

db.getCollection("vinculos").aggregate(
    [
        { 
            "$match" : {
                "$nor" : [
                    {
                        "status.codigo" : "1"
                    }, 
                    {
                        "tipo" : {
                            "$in" : [
                                "amizade", 
                                "nao-sugerir"
                            ]
                        }
                    }, 
                    {
                        "vinculo.objeto" : ObjectId("5d6821c70215c9e5e5fd096b")
                    }
                ]
            }
        }
    ]
)

第二次尝试(无结果)

db.getCollection("vinculos").aggregate(
    [
        { 
            "$match" : {
                "$and" : [
                    {
                        "status.codigo" : {
                            "$ne" : "1"
                        }
                    }, 
                    {
                        "tipo" : {
                            "$nin" : [
                                "amizade", 
                                "nao-sugerir"
                            ]
                        }
                    }, 
                    {
                        "vinculo.objeto" : {
                            "$ne" : ObjectId("5d6821c70215c9e5e5fd096b")
                        }
                    }
                ]
            }
        }
    ]
)

我需要退回其他 13 件商品,有什么建议吗?

【讨论】:

    【解决方案4】:

    TLDR;你想要一个与非门......

    db.getCollection('test').find({ $or: [ {institution_type:{$ne:'A'}}, {type:{$ne:'C'}} ]})
    

    ...然后去感谢(upvote)this answer(不是我)

    或 NOR 门...

    db.getCollection('test').find({ $nor: [{institution_type:'A', type:'C'}] })
    

    加长版...

    我在 MongoDB 中找不到 logical operator 来处理 $nand 逻辑,所以我“构建”了逻辑(见下文)。

    $nand 运算符有一个 open feature request,但我不会屏住呼吸(创建于 2014 年)。

    $nor 也可以做你想做的事,如果你反转 $ne 逻辑。

    (但是 IMO - 感觉就像我们在贬低这种行为 - 只使用反向 $not 行为,而无视数组的 $and 行为......但它有效,所以没有错)。

    db.getCollection('test').insertMany([
        { "institution_type" : "A", "type" : "C" },
        { "institution_type" : "A", "type" : "D" },
        { "institution_type" : "B", "type" : "C" },
        { "institution_type" : "B", "type" : "D" }
    ])
    
    // "NAND gate": (NOT A) OR (NOT B) -> correct 3x results
    db.getCollection('test').find({ $or: [ {institution_type:{$not:{$eq:'A'}}}, {type:{$not:{$eq:'C'}}} ]})
    
    // or simpler...
    db.getCollection('test').find({ $or: [ {institution_type:{$ne:'A'}}, {type:{$ne:'C'}} ]})
    
    // or simpler still...
    
    // "NOR gate": (NOT A) AND (NOT B) -> correct 3x results
    db.getCollection('test').find({ $nor: [{institution_type:'A', type:'C'}] })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 2023-03-10
      相关资源
      最近更新 更多