2015-11-16 7 views
5

che voglio raggiungere $ somma con $ cond avendo $ o sulla proprietà:

db.collectionName.aggregate(
{ 
    "$group": { 
    "_id":'$created_at', 
    "count": {"$sum": 1}, 
    "count_failure": { 
     "$sum": { 
      "$cond": [ 
       { 
       "$id": 
        { "$in": [ 0,100,101,102,103,104,105 ] } 
       }, 
       1, 
       0 
       ] 
      } 
     } 
    } 
} 
) 

Ma l'errore dice: Invalid operator "$id"

Cosa c'è di sbagliato nella sintassi? O sto scrivendo query in modo errato.

Attualmente sto ottenere tale risultato con:

db.collectionName.aggregate(
{ 
    "$group": { 
    "_id":'$created_at', 
    "count": {"$sum": 1}, 
    "count_failure": { 
     "$sum": { 
      "$cond": [ 
       { 
       "$or":[ 
        { "$eq": [ "$id", 0 ] }, 
        { "$eq": [ "$id", 100 ]}, 
        { "$eq": [ "$id", 101 ]}, 
        { "$eq": [ "$id", 102 ]}, 
        { "$eq": [ "$id", 103 ]}, 
        { "$eq": [ "$id", 104 ]}, 
        { "$eq": [ "$id", 105 ]} 
       ] 
       }, 
       1, 
       0 
       ] 
      } 
     } 
    } 
} 
) 

risposta

8

Il confronto su $setIsSubset è un'opzione più breve rispetto alla condizione $or che si sta utilizzando, anche se è ancora fondamentalmente valido fare ciò che stai facendo.

L'unico problema con $setIsSubset è che ogni argomento è una matrice, quindi è necessario convertire il singolo elemento come una matrice di elementi singoli. Questo è abbastanza facile utilizzando $map:

db.collectionName.aggregate([ 
    { "$group": { 
     "_id": "$createdAt", 
     "count": { "$sum": 1 }, 
     "count_failure": { 
      "$sum": { 
       "$cond": [ 
        { "$setIsSubset": [ 
         { "$map": { 
          "input": ["A"], 
          "as": "el", 
          "in": "$id" 
         }}, 
         [ 0,100,101,102,103,104,105 ], 
        ]}, 
        1, 
        0 
       ] 
      } 
     } 
    }}  
]) 

Oppure, se preferite, quindi corrisponde alla matrice di argomenti contro il valore singolare, invece, con $anyElementTrue:

db.collectionName.aggregate([ 
    { "$group": { 
     "_id": "$createdAt", 
     "count": { "$sum": 1 }, 
     "count_failure": { 
      "$sum": { 
       "$cond": [ 
        { "$anyElementTrue": { "$map": { 
         "input": [ 0,100,101,102,103,104,105 ], 
         "as": "el", 
         "in": { "$eq": [ "$$el", "$id" ] } 
        }}}, 
        1, 
        0 
       ] 
      } 
     } 
    }} 
]) 

Qualora il $map è piuttosto che attraversano gli argomenti da abbinare al singolare piuttosto che forzare il singolare in una matrice.

E, naturalmente, dal momento che entrambe le forme è la fornitura essenzialmente true/false al $cond allora si può solo invertire la logica con $not ove richiesto:

db.collectionName.aggregate([ 
    { "$group": { 
     "_id": "$createdAt", 
     "count": { "$sum": 1 }, 
     "count_failure": { 
      "$sum": { 
       "$cond": [ 
        { "$not": [{ "$anyElementTrue": { "$map": { 
         "input": [ 0,100,101,102,103,104,105 ], 
         "as": "el", 
         "in": { "$eq": [ "$$el", "$id" ] } 
        }}}]}, 
        1, 
        0 
       ] 
      } 
     } 
    }} 
]) 

Dipende molto da come la si guarda, ma semplicemente come fornito argomenti quindi non si guadagna nulla sul modulo originale con $or. Potrebbe sembrare un po 'più pulito e "più facile da digitare", ma in genere non sarei "digitando" tale logica nella pipeline di aggregazione direttamente, ma piuttosto generando quella parte della struttura basata su un elenco semplice in primo luogo:

cioè

var failList = [ 0,100,101,102,103,104,105 ]; 

var orCondition = failList.map(function(el) { 
    return { "$eq": [ "$id", el ] } 
}) 

e poi basta con il re-mapped contenuti di matrice nella definizione cantiere:

{ "$group": { 
     "_id": "$createdAt", 
     "count": { "$sum": 1 }, 
     "count_failure": { 
      "$sum": { 
       "$cond": [ 
        { "$or": orCondition }, 
        1, 
        0 
       ] 
      } 
     } 
    }} 
]) 

in qualunque modo la si guardi, ricordatevi che è tutto a strutture di dati e si dispone di processi di base per manipolare. Sia all'interno dell'elaborazione della pipeline che nella costruzione della pipeline stessa.

+0

1o modo un po 'difficile. Il secondo è facile. Sebbene ci dovrebbe essere facile $ o in $ gruppo? Spero che mongo rilasci questa funzione. –

+0

@SomnathMuluk Penso che tu intenda "3rd way" visti i tre approcci mostrati, e per la cronologia quasi tutto il mio codice che fa qualcosa del genere fa così, poiché è l'approccio logico. Se si intende che si desidera una clausola '$ in', allora si consideri che si sta chiedendo questo per alimentare a' $ cond' in primo luogo, quindi qual è esattamente la sintassi per tale operazione? Dove specifichi il campo a cui vuoi confrontare? Siete invitati a pubblicare un [JIRA] (https://jira.mongodb.org/secure/Dashboard.jspa) con qualsiasi suggerimento del genere. –

+1

Sì, voglio dire che il 2 ° e il 3 ° sono facili. E c'è già un suggerimento dato come https://jira.mongodb.org/browse/SERVER-6146 –

0

Penso che $ a non è un operatore di aggregazione pipeline.

+0

Come utilizzare "$ setIsSubset" anziché "$ In"? –

+0

Sintassi: '{$ setIsSubset: [, ]}'. Devi mettere il tuo elemento "id" in una matrice.Ma ripensandoci, penso che non sia la soluzione migliore. – hecnabae

0

In primo luogo è necessario creare un elenco di $id utilizzando $map nel progetto e quindi utilizzare setIsSubset nel gruppo come di seguito:

db.collectionName.aggregate([{ 
    "$project": { 
    "idsArray": { 
     "$map": { 
     "input": ["A"], 
     "as": "el", 
     "in": { 
      "$cond": [{ 
       "$eq": ["$$el", "A"] 
      }, "$id", 
      null 
      ] 
     } 
     } 
    } 
    } 
}, { 
    "$group": { 
    "_id": "$created_at", 
    "count": { 
     "$sum": 1 
    }, 
    "count_failure": { 
     "$sum": { 
     "$cond": [{ 
      "$setIsSubset": ["$idsArray", [ 
       0, 
       100, 
       101, 
       102, 
       103, 
       104, 
       105 
      ]] 
      }, 
      1, 
      0 
     ] 
     } 
    } 
    } 
}])