2015-11-16 5 views
5

Ich möchte $ Summe mit $ Cond zu erreichen, indem $ oder auf Eigenschaft:

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

Aber Fehler sagt: Invalid operator "$id"

Was ist falsch an der Syntax? Oder ich schreibe eine Anfrage falsch.

Ich Erreichung dieses Ziels Derzeit:

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

Antwort

8

Der Vergleich auf $setIsSubset ist eine kürzere Option als die $or Bedingung, die Sie verwenden, obwohl es immer noch grundsätzlich gilt, das zu tun, was du tust.

Der einzige Haken bei $setIsSubset ist, dass jedes Argument ein Array ist, so dass Sie das einzelne Element als einzelnes Element-Array konvertieren müssen. Dies ist leicht genug, um $map mit:

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

Oder wenn Sie es bevorzugen, dann das Array von Argumenten gegen die singuläre Wert übereinstimmen stattdessen mit $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 
       ] 
      } 
     } 
    }} 
]) 

Wo die $map vielmehr die Argumente Fahren auf passen Sie dem Singular an, anstatt den Singular in ein Array zu zwingen.

Und natürlich, da entweder Form im Wesentlichen true/false zum $cond liefert dann können Sie nur die Logik mit $not umkehren, wo erforderlich:

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

Es hängt wirklich davon ab, wie man es betrachtet, sondern einfach als geliefert Argumente, dann Sie wirklich nichts über das Originalformular mit $or gewinnen. Es könnte ein wenig sauberer und "einfacher zu typisieren" sein, aber typischerweise würde ich solche Logik nicht direkt in die Aggregationspipeline "eingeben", sondern stattdessen diesen Teil der Struktur auf der Grundlage einer einfachen Liste erzeugen:

dh

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

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

und dann nur die re-mapped Array Inhalt in der Pipeline Definition:

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

Wie auch immer man es betrachtet, erinnern sie alle Strukturen nur Daten ist und Sie grundlegende Prozesse zum Manipulieren. Sowohl innerhalb der Pipeline-Verarbeitung als auch im Pipeline-Bau selbst.

+0

1. Weg etwas hart. 2. ist einfach. Obwohl es eine einfache $ oder in $ Gruppe geben sollte? Hope Mongo veröffentlicht diese Funktion. –

+0

@SomnathMuluk Ich denke, du meinst "3rd way" angesichts der drei gezeigten Ansätze, und für den Rekord fast alles von meinem Code tun, so etwas tut es so, wie es der logische Ansatz ist. Wenn Sie meinen, dass Sie eine '$ in'-Klausel haben wollen, dann denken Sie daran, dass Sie darum bitten, an $ cond zu füttern, also, was genau ist die Syntax für solch eine Operation? Wo geben Sie das Feld an, mit dem Sie vergleichen möchten? Sie können gerne einen [JIRA] (https://jira.mongodb.org/secure/Dashboard.jspa) mit einem solchen Vorschlag veröffentlichen. –

+1

Ja ich meine 2. und 3. sind einfach. Und da gibt es bereits einen Vorschlag als https://jira.mongodb.org/browse/SERVER-6146 –

0

denke ich, dass in Bediener nicht eine Ansammlung Pipeline $ ist.

+0

Wie verwendet man "$ setIsSubset" anstelle von "$ In"? –

+0

Syntax: '{$ setIsSubset: [, ]}' '. Sie müssen Ihr Element "ID" in eine Matrix einfügen.Aber auf den zweiten Gedanken denke ich, dass es nicht die beste Lösung ist. – hecnabae

0

Zuerst Sie eine Liste von $id mit $map in Projekt erstellen sollten und dann setIsSubset in der Gruppe verwenden, wie unten:

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 
     ] 
     } 
    } 
    } 
}]) 
Verwandte Themen