MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

MongoDB elemmatch più elementi nell'array

Non puoi restituire più elementi di un array che corrispondono ai tuoi criteri in nessuna forma di un .find() di base interrogazione. Per abbinare più di un elemento devi usare .aggregate() metodo invece.

La differenza principale qui è che la "query" fa esattamente ciò per cui è destinata e corrisponde a "documenti" che soddisfano le tue condizioni. Puoi provare a utilizzare il $ posizionale operatore all'interno di un argomento di proiezione, ma le regole stabiliscono che corrisponderà solo al "primo" elemento dell'array che soddisfa le condizioni della query.

Per "filtrare" più elementi dell'array, procedere come segue:

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Unwind the array to denormalize
    { "$unwind": "$filtermetric" },

    // Match specific array elements
    { "$match": { "filtermetric.class": "s2" } },

    // Group back to array form
    { "$group": {
        "_id": "$_id",
        "filtermetric": { "$push": "$filtermetric" }
    }}
])

Nelle versioni moderne di MongoDB che sono la versione 2.6 o successiva puoi farlo con $redact :

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Redact the entries that do not match
    { "$redact": {
        "$cond": [
            { "$eq": [ { "$ifNull": [ "$class", "s2" ] }, "s2" ] },
            "$$DESCEND",
            "$$PRUNE"
        ]
    }}
])

Questa è probabilmente la tua opzione più efficiente, ma è ricorsiva, quindi considera prima la struttura del tuo documento poiché lo stesso campo con nome non può esistere con nessun'altra condizione a nessun livello.

Forse più sicura ma utile solo quando i risultati nell'array sono "veramente unici" è questa tecnica con $map e $setDifference :

db.sample.aggregate([
    { "$project": {
        "filtermetric": { "$setDifference": [
            { "$map": [
                "input": "$filtermetric",
                "as": "el",
                "in": {"$cond": [
                    { "$eq": [ "$$el.class", "s2" ] },
                    "$$el",
                    false
                ]}
            ]},
            [false]
        ]}
    }}
])

Notando anche che in entrambi i $group e $project fasi della pipeline operativa di cui hai bisogno per specificare tutti i campi che intendi restituire nei documenti dei risultati da quella fase.

La nota finale è che $elemMatch non è richiesto quando si interroga solo il valore di una singola chiave all'interno di una matrice. La "notazione punto" è preferita e consigliata quando si accede a una sola chiave dell'array. $elemMatch dovrebbe essere necessario solo quando le chiavi "multiple" nel documento all'interno dell'array "element" devono corrispondere a una condizione di query.