Domanda

Gli oggetti nel database hanno un'array 'Properties', che può contenere oggetti diversi.Alcuni di loro presentano numeri o gamme e sembrano:

{'value': 10}
.

o

{'minValue': 4, 'maxValue': 8}
.

Quando interroga la collezione per un numero specifico, come X, voglio trovare tutti i documenti in cui entrambi i dati equivalgono x o minvalue <= x <= maxvalue.Il mio primo tentativo di una query sembra

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

L'inconveniente è che se la matrice delle proprietà tiene più oggetti che specificano minvalue e maxvalue, x può essere tra nessuno di essi.Ad esempio

"properties" : [
    {
        "minValue" : 4,
        "maxValue" : 6
    },
    {
        "minValue" : 10,
        "maxValue" : 20
    }
]
.

si abbinano per X= 8. La query può essere migliorata in modo che la struttura dell'oggetto all'interno delle proprietà sia rispettata?

È stato utile?

Soluzione

Si vuole praticamente usare $elemMatch combinato con un $or CondizioneIn questa forma:

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

che copre riunisce i documenti che contengono l'intervallo e il possibile altro nome chiave per il campo nelle proprietà.

Ma tieni presente che i documenti corrispondenti sono diversi per abbinare gli elementi in un array.Quindi se ti aspetti solo gli elementi dell'array che corrispondono ad essere restituiti e ne hai più di uno, quindi usi il modulo aggregato:

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" }
    }}
])
.

Ma se ci sarà solo una corrispondenza di cui sei sicuro di usare semplicemente la proiezione con la ricerca:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top