MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

SailsJS &MongoDB Aggregation Framework Probleme mit benutzerdefinierten Abfragen

Ihre erste Anfrage war auf dem richtigen Weg, da Sie den falschen Pipeline-Operator verwendet haben.

Artist.native(function(err,collection) {

    collection.aggregate(
        [
            { "$project": {
                "_id": 1,
                "name": 1,
                "total": { "$size": "$dubs" }
            }}
        ],
        function(err,result) {
          if (err) return res.serverError(err);
          console.log(result);
        }
})

Natürlich der $size -Operator dort erfordert, dass Sie eine MongoDB-Version 2.6 oder höher benötigen, was Sie wahrscheinlich inzwischen tun sollten, aber Sie können immer noch dasselbe ohne den Operator zum Messen der Array-Länge tun:

Artist.native(function(err,collection) {

    collection.aggregate(
        [
            { "$project": {
                "_id": 1,
                "name": 1,
                "dubs": {
                    "$cond": [
                       { "$eq": [ "$dubs", [] ] },
                       [0],
                       "$dubs"
                    ]
                }
            }},
            { "$unwind": "$dubs" },
            { "$group": {
                "_id": "$_id",
                "name": { "$first": "$name" },
                "total": { 
                    "$sum": {
                        "$cond": [
                            { "$eq": [ "$dubs", 0 ] },
                            0,
                            1
                        ]
                    }
                }
            }}
        ],
        function(err,result) {
          if (err) return res.serverError(err);
          console.log(result);
        }
})

Das macht dasselbe, indem es die Mitglieder des Arrays zählt, aber stattdessen müssten Sie $unwind die Array-Elemente, um sie zu zählen. Es kann also immer noch durchgeführt werden, ist aber nicht so effizient.

Außerdem müssen Sie die Fälle handhaben, in denen das Array wirklich leer, aber vorhanden ist, weil $unwind behandelt ein leeres Array [] . Wenn kein Inhalt vorhanden war, wurde das Dokument, das ein solches Element enthielt, aus den Ergebnissen entfernt. Auf ähnliche Weise müssten Sie $ifNull um ein Array zu setzen, wo das Dokument nicht einmal ein Element für $unwind um nicht zu einem Fehler zu führen.

Wirklich, wenn Sie beabsichtigen, diese Art von Abfrage regelmäßig durchzuführen, dann sollten Sie ein "Gesamt"-Feld im Dokument beibehalten, anstatt zu versuchen, es zuerst zu berechnen. Verwenden Sie den $inc Operator zusammen mit Operationen wie $push und $pull um eine Übersicht über die aktuelle Array-Länge zu behalten.

Das weicht ein wenig von der allgemeinen Waterline-Philosophie ab, aber Sie haben bereits native Aggregationsvorgänge eingeführt, und es ist nicht mehr weit hergeholt zu erkennen, dass Sie durch die Verwendung nativer Vorgänge auch in anderen Bereichen eine bessere Leistung erzielen.

Also mit Dokumenten wie diesen:

{
  "dubs": [{},{},{}],
  "name": "The Doors",
  "createdAt": "2014-12-15T15:24:26.216Z",
  "updatedAt": "2014-12-15T15:24:26.216Z",
  "id": "548efd2a436c850000353f4f"
},
{
  "dubs": [],
  "name": "The Beatles",
  "createdAt": "2014-12-15T20:30:33.922Z",
  "updatedAt": "2014-12-15T20:30:33.922Z",
  "id": "548f44e90630d50000e2d61d"
}

Sie erhalten jeweils genau die Ergebnisse, die Sie sich wünschen:

{
    "_id" : ObjectId("5494b79d7e22da84d53c8760"),
    "name" : "The Doors",
    "total" : 3
},
{
    "_id" : ObjectId("5494b79d7e22da84d53c8761"),
    "name" : "The Beatles",
    "total" : 0
}