如何创建一个 mongodb 查询来查找一个数字是否在两个字段之间?

TeT*_*TeT 3 mongodb mongodb-query aggregation-framework

数据库中的对象有一个“属性”数组,可以容纳不同的对象。其中一些显示数字或范围,看起来像:

{'value': 10}
Run Code Online (Sandbox Code Playgroud)

或者

{'minValue': 4, 'maxValue': 8}
Run Code Online (Sandbox Code Playgroud)

当查询特定数字(如 X)的集合时,我想找到值等于 X 或 minValue <= X <= maxValue 的所有文档。我第一次尝试查询看起来像

db.Pool0.find({$or: [{'properties.value': X}, {'properties.minValue': {$lte: X}, 'properties.maxValue': {$gte: X}}]}, {'_id': 1}).pretty()
Run Code Online (Sandbox Code Playgroud)

缺点是如果属性数组包含多个指定 minValue 和 maxValue 的对象,则 X 可以介于其中任何一个之间。例如

"properties" : [
    {
        "minValue" : 4,
        "maxValue" : 6
    },
    {
        "minValue" : 10,
        "maxValue" : 20
    }
]
Run Code Online (Sandbox Code Playgroud)

将匹配 X = 8。能否改进查询以便尊重属性中的对象结构?

Nei*_*unn 7

你基本上想$elemMatch结合使用$or这种形式的条件:

db.collection.find({
    "$or": [
        {
            "properties": { "$elemMatch": {
                "minValue": { "$lte": 8 },
                "maxValue": { "$gte": 8 }
            }}
        },
        {
            "properties.value": 8
        }
    ]
})
Run Code Online (Sandbox Code Playgroud)

这包括满足包含范围的文档以及属性中字段的可能的其他键名称。

但请记住,匹配文档与匹配数组中的元素不同。因此,如果您只是希望返回匹配的数组元素并且您有多个元素,那么您可以使用聚合形式:

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

但是,如果您确定只有一个匹配项,那么只需将投影与 find 结合使用:

db.collection.find(
    { 
        "$or": [
            {
                "properties": { "$elemMatch": {
                    "minValue": { "$lte": 8 },
                    "maxValue": { "$gte": 8 }
                }}
            },
            {
            "properties.value": 8
            }
        ]
    },
    { "properties.$": 1 }
)
Run Code Online (Sandbox Code Playgroud)