数据库中的对象具有'属性'数组,可以容纳不同的对象。其中一些呈现数字或范围,看起来像:
{'value': 10}
或
{'minValue': 4, 'maxValue': 8}
当查询特定数字(如X)的集合时,我想查找其中值等于X或minValue< = X< = maxValue的所有文档。我第一次尝试查询看起来像是
db.Pool0.find({$or: [{'properties.value': X}, {'properties.minValue': {$lte: X}, 'properties.maxValue': {$gte: X}}]}, {'_id': 1}).pretty()
缺点是如果properties数组包含指定minValue和maxValue的多个对象,则X可以位于其中任何一个之间。例如
"properties" : [
{
"minValue" : 4,
"maxValue" : 6
},
{
"minValue" : 10,
"maxValue" : 20
}
]
将匹配X = 8.是否可以改进查询以便尊重属性中的对象结构?
答案 0 :(得分:4)
您基本上希望在此表单中使用$elemMatch
并结合$or
条件:
db.collection.find({
"$or": [
{
"properties": { "$elemMatch": {
"minValue": { "$lte": 8 },
"maxValue": { "$gte": 8 }
}}
},
{
"properties.value": 8
}
]
})
这包括满足包含范围的文档以及属性中字段的可能的其他键名。
但请记住,匹配文档与数组中的匹配元素不同。因此,如果您只是希望返回匹配的数组元素并且您有多个,那么您使用聚合形式:
db.collection.aggregate([
// Matching documents is still good practice
{ "$match": {
"$or": [
{
"properties": { "$elemMatch": {
"minValue": { "$lte": 8 },
"maxValue": { "$gte": 8 }
}}
},
{
"properties.value": 8
}
]
}},
// Unwind to de-normalize
{ "$unwind": "$properties" },
// Then match to filter the elements
{ "$match": {
"$or": [
{
"properties.minValue": { "$lte": 8 },
"properties.maxValue": { "$gte": 8 }
},
{ "properties.value": 8 }
]
}},
// Reconstruct the filtered array
{ "$group": {
"_id": "$_id",
"properties": { "$push": "$properties" }
}}
])
但是如果只有一个你确定的匹配,那么只需使用find:
db.collection.find(
{
"$or": [
{
"properties": { "$elemMatch": {
"minValue": { "$lte": 8 },
"maxValue": { "$gte": 8 }
}}
},
{
"properties.value": 8
}
]
},
{ "properties.$": 1 }
)