MongoDB:无法规范化查询:BadValue投影不能包含包含和排除的混合。

44

我是MongoDB和CakePHP的新手。

当我编写以下查询时,它将会执行得很好。

db.testData.find()
{
    "_id" : ObjectId("53d1f79db8173a625961ff3d"),
    "name" : "sadikhasan",
    "created" : ISODate("2014-07-25T06:22:21.701Z")
}

当我运行以下查询以仅获取name时,它返回一个错误:
db.testData.find({},{name:1, created:0})
error: {
    "$err" : "Can't canonicalize query: BadValue Projection cannot 
              have a mix of inclusion and exclusion.",
    "code" : 17287
}

当我运行以下查询以仅获取具有_id:0name时,它可以成功执行:
db.testData.find({},{name:1, _id:0})
{ "name" : "sadikhasan" }

我的问题是,当我在投影列表中写入created:0时,为什么会出现错误。提前感谢您的帮助。

4个回答

103

您不能混合使用包含和排除, _id 字段是唯一的例外。

举个例子,如果您有以下内容:

{
   "_id": ObjectId("53d1fd30bdcf7d52c0d217de"),
   "name": "bill",
   "birthdate": ISODate("2014-07-80T00:00:00.000Z"),
   "created": ISODate("2014-07-25T06:44:38.641Z")
}
如果你只想要“名字”和“出生日期”,你需要这样做:
db.collection.find({},{ "_id": 0, "name": 1, "birthdate": 1 })

或者这个:

db.collection.find({},{ "_id": 0, "created": 0 })

但是除了“_id”之外,不允许“混合”任何其他操作。

db.collection.find({},{ "_id": 0, "name": 1, "created": 0 })

这也将产生一个错误。

所有这些都在手册页面中有详细介绍。


1
当我想要投影列表时,我总是需要传递_id:0吗? - Sadikhasan
@Sadikhasan 不是的。这只是为了排除默认情况下始终包括的“_id”字段。示例中提供了一个链接,详细解释了这一点。还有其他各种教程示例,你应该花些时间阅读。 - Neil Lunn
1
他们为什么选择这种设计的想法呢?允许在查询中过分使用语言上有些合理。 - Richard
我收到了这个错误,因为我的投影是{id:0, name:1}。我不小心删除了ID字段名称的下划线。它应该是{_id:0, name:1}。我不理解MongoDB术语“BadValue Projection”,但这个答案说明了它所指的内容。 - Mr. Lance E Sloan

6
它会抛出错误“无法规范化查询:BadValue投影不能包含混合的包含和排除”,因为您混合了包含和排除。其中,“1”代表包含,“0”代表排除。您可以在查询中使用0或1。因此,如果您只想查看_id和name字段,可以使用以下任一方法: 1)包含:
              db.testdata.find({}, {_id:1,name:1})

或者2)排除:

              db.testdata.find({},{created:0})

在上述两种情况中,它将仅显示“_id”和“name”字段。

默认的 _id:1 总是包含吗? - Sadikhasan
是的,1表示包含。因此字段名称为:inclusion(1)/exclusion(0)。 - Bipul Sinha

4

我遇到了同样的问题。这意味着你不能同时告诉MongoDB选择一个特定的字段并取消选择另一个字段。

这是错误的,不能在选择选项中像这样指定。 错误:-Projection不能同时包含包含和排除。

reviewSchema.pre(/^find/, function (next) {
    this.populate({
        path: 'tour',
        select: 'name -__v'
    })
    next();
});

正确的格式。

reviewSchema.pre(/^find/, function (next) {
    this.populate({
        path: 'tour',
        select: 'name' // Removed -__v
    })
    next();
});

2
这是一个问题还是一个答案? - PV8

1
简单来说,你可以告诉MongoDB你想要哪些字段或不想要哪些字段。也就是说,在选择方法中,你只需要提到所需或不需要的字段,如下所示。

find({<!--query here--!>}).select({

        password: 0,
        allowed_ip: 0,
        username: 0,
        password: 0,
        __v: 0,
        _id: 0
    });

这应该是零(排除/非必需)或一(包含/必填字段)。干杯!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接