是否可以将位置运算符'$'与深层嵌套文档数组上的查询结合使用?
考虑定义“用户”的以下嵌套文档:
{
username: 'test',
kingdoms: [
{
buildings: [
{
type: 'castle'
},
{
type: 'treasury'
},
...
]
},
...
]
}
我们想为特定用户返回“城堡”,例如形式如下:
{
kingdoms: [{
buildings: [{
type: 'castle'
}]
}]
}
因为你不能两次使用$运算符(https://jira.mongodb.org/browse/server-831)我知道我也不能查询某个特定的王国,所以我正在尝试为第n个王国写一个查找语句。
这在更新深层嵌套的子文档(Mongodb update deeply nested subdocument)时似乎有意义,但我在查找查询方面的成功较少。
我可以通过查询返回第一个王国的建筑物:
db.users.findOne(
{ username: 'test' },
{ kingdoms: {$slice: [0, 1]}, 'kingdom.buildings': 1 }
);
但是这会使所有返回那个王国的建筑物。
按照位置运算符的单级示例,我正在尝试这样的查询:
db.users.findOne(
{ username: 'test', 'kingdoms.buildings.type': 'castle' },
{ kingdoms: {$slice: [n, 1]}, 'kingdom.buildings.$': 1 }
);
以形式:
db.collection.find( { <array.field>: <value> ...}, { "<array>.$": 1 } )
如文档http://docs.mongodb.org/manual/reference/operator/projection/positional/#proj.S
中所述然而,这失败并出现错误:
Positional operator does not match the query specifier
大概是因为王国建筑不被视为阵列。我也试过 kingdoms.0.buildings
这很令人困惑,因为这似乎适用于更新(根据Mongodb update deeply nested subdocument)
我是否只是语法错误或者不支持?如果有,有办法实现类似的东西吗?
答案 0 :(得分:3)
您收到错误
db.users.findOne(
{ username: 'test', 'kingdoms.buildings.type': 'castle' },
{ kingdoms: {$slice: [n, 1]}, 'kingdom.buildings.$': 1 }
);
因为存在拼写错误(&#34; kingdom.buildings。$&#34;应该是&#34;王国 s .buildings。$&#34;)。 /> 但是,这种方式无法实现您的期望 $ 总是针对 kingdoms.buildings - 第一个数组的王国。
这是一种应该能够解决问题的方法 (V2.6 +要求)
db.c.aggregate([ {
$match : {
username : 'test',
'kingdoms.buildings.type' : 'castle'
}
}, {
$project : {
_id : 0,
kingdoms : 1
}
}, {
$redact : {
$cond : {
"if" : {
$or : [ {
$gt : [ "$kingdoms", [] ]
}, {
$gt : [ "$buildings", [] ]
}, {
$eq : [ "$type", "castle" ]
} ]
},
"then" : "$$DESCEND",
"else" : "$$PRUNE"
}
}
} ]).pretty();
仅保留王国的第一个元素
db.c.aggregate([ {
$match : {
username : 'test',
'kingdoms.buildings.type' : 'castle'
}
}, {
$redact : {
$cond : {
"if" : {
$or : [ {
$gt : [ "$kingdoms", [] ]
}, {
$gt : [ "$buildings", [] ]
}, {
$eq : [ "$type", "castle" ]
} ]
},
"then" : "$$DESCEND",
"else" : "$$PRUNE"
}
}
}, {
$unwind : "$kingdoms"
}, {
$group : {
_id : "$_id",
kingdom : {
$first : "$kingdoms"
}
}
}, {
$group : {
_id : "$_id",
kingdoms : {
$push : "$kingdom"
}
}
}, {
$project : {
_id : 0,
kingdoms : 1
}
} ]).pretty();