2016-07-11 28 views
1

Im Wesentlichen versuche ich OUT-Filialdokumente und Sub-Filialdokumente, die "trashed" wurden, zu filtern. Hier ist eine abgespeckte Version meines Schema:

permitSchema = { 
    _id, 
    name, 
    ... 
    feeClassifications: [ 
    new Schema({ 
     _id, 
     _trashed, 
     name, 
     fees: [ 
     new Schema({ 
      _id, 
      _trashed, 
      name, 
      amount 
     }) 
     ] 
    }) 
    ], 
    ... 
} 

Also ich bin in der Lage, die Wirkung ich mit feeClassifications wollen zu bekommen. Aber ich kämpfe, um einen Weg zu finden, den gleichen Effekt für feeClassifications.fees auch zu haben.

So funktioniert dies wie gewünscht:

Permit.aggregate([ 
    { $match: { _id: mongoose.Types.ObjectId(req.params.id) }}, 
    { $project: { 
    _id: 1, 
    _name: 1, 
    feeClassifications: { 
     $filter: { 
     input: '$feeClassifications', 
     as: 'item', 
     cond: { $not: {$gt: ['$$item._trashed', null] } } 
     } 
    } 
    }} 
]) 

Aber ich möchte auch fees die verschachtelte Array filtern. Ich habe ein paar Dinge ausprobiert, einschließlich:

Permit.aggregate([ 
    { $match: { _id: mongoose.Types.ObjectId(req.params.id) }}, 
    { $project: { 
    _id: 1, 
    _name: 1, 
    feeClassifications: { 
     $filter: { 
     input: '$feeClassifications', 
     as: 'item', 
     cond: { $not: {$gt: ['$$item._trashed', null] } } 
     }, 
     fees: { 
     $filter: { 
      input: '$fees', 
      as: 'fee', 
      cond: { $not: {$gt: ['$$fee._trashed', null] } } 
     } 
     } 
    } 
    }} 
]) 

, die die mongodb docs in der Nähe zu folgen scheint. Aber ich habe den Fehler: this object is already an operator expression, and can't be used as a document expression (at 'fees')

Update: -----------

Wie gewünscht, hier ist ein Beispieldokument:

{ 
    "_id" : ObjectId("57803fcd982971e403e3e879"), 
    "_updated" : ISODate("2016-07-11T19:24:27.204Z"), 
    "_created" : ISODate("2016-07-09T00:05:33.274Z"), 
    "name" : "Single Event", 
    "feeClassifications" : [ 
     { 
      "_updated" : ISODate("2016-07-11T19:05:52.418Z"), 
      "_created" : ISODate("2016-07-11T17:49:12.247Z"), 
      "name" : "Event Type 1", 
      "_id" : ObjectId("5783dc18e09be99840fad29f"), 
      "fees" : [ 
       { 
        "_updated" : ISODate("2016-07-11T18:51:10.259Z"), 
        "_created" : ISODate("2016-07-11T18:41:16.110Z"), 
        "name" : "Basic Fee", 
        "amount" : 156.5, 
        "_id" : ObjectId("5783e84cc46a883349bb2339") 
       }, 
       { 
        "_updated" : ISODate("2016-07-11T19:05:52.419Z"), 
        "_created" : ISODate("2016-07-11T19:05:47.340Z"), 
        "name" : "Secondary Fee", 
        "amount" : 50, 
        "_id" : ObjectId("5783ee0bad7bf8774f6f9b5f"), 
        "_trashed" : ISODate("2016-07-11T19:05:52.410Z") 
       } 
      ] 
     }, 
     { 
      "_updated" : ISODate("2016-07-11T18:22:21.567Z"), 
      "_created" : ISODate("2016-07-11T18:22:21.567Z"), 
      "name" : "Event Type 2", 
      "_id" : ObjectId("5783e3dd540078de45bbbfaf"), 
      "_trashed" : ISODate("2016-07-11T19:24:27.203Z") 
     } 
    ] 
} 

Und hier ist die gewünschte Ausgabe („trashed“ Subdokumente von beiden feeClassifications uND fees ausgeschlossen):

{ 
    "_id" : ObjectId("57803fcd982971e403e3e879"), 
    "_updated" : ISODate("2016-07-11T19:24:27.204Z"), 
    "_created" : ISODate("2016-07-09T00:05:33.274Z"), 
    "name" : "Single Event", 
    "feeClassifications" : [ 
     { 
      "_updated" : ISODate("2016-07-11T19:05:52.418Z"), 
      "_created" : ISODate("2016-07-11T17:49:12.247Z"), 
      "name" : "Event Type 1", 
      "_id" : ObjectId("5783dc18e09be99840fad29f"), 
      "fees" : [ 
       { 
        "_updated" : ISODate("2016-07-11T18:51:10.259Z"), 
        "_created" : ISODate("2016-07-11T18:41:16.110Z"), 
        "name" : "Basic Fee", 
        "amount" : 156.5, 
        "_id" : ObjectId("5783e84cc46a883349bb2339") 
       } 
      ] 
     } 
    ] 
} 

Antwort

1

Da wir filtern möchten sowohl die äußere und Inne R-Array-Felder, können wir die $map Variablenoperator verwenden, die ein Array mit den "Werten" zurückgeben, die wir wollen.

Im Ausdruck $map bieten wir eine logische $cond itional $filter zum Entfernen der nicht übereinstimmenden Dokumente aus dem Feld Dokument und Filialdokument Array.

Die Bedingungen sind $lt, die True zurückgeben, wenn das Feld "_trashed" in dem Unterdokument und dem Feld Unterdokumentarray nicht vorhanden ist.

Beachten Sie, dass in der $cond Ausdruck wir auch falsch für die <false case> zurückgeben. Natürlich müssen wir Filter auf das $map Ergebnis anwenden, um alle false zu entfernen.

Permit.aggregate(
    [ 
     { "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } }, 
     { "$project": { 
      "_updated": 1, 
      "_created": 1, 
      "name": 1, 
      "feeClassifications": { 
       "$filter": { 
        "input": { 
         "$map": { 
          "input": "$feeClassifications", 
          "as": "fclass", 
          "in": { 
           "$cond": [ 
            { "$lt": [ "$$fclass._trashed", 0 ] }, 
            { 
             "_updated": "$$fclass._updated", 
             "_created": "$$fclass._created", 
             "name": "$$fclass.name", 
             "_id": "$$fclass._id", 
             "fees": { 
              "$filter": { 
               "input": "$$fclass.fees", 
               "as": "fees", 
               "cond": { "$lt": [ "$$fees._trashed", 0 ] } 
              } 
             } 
            }, 
            false 
           ] 
          } 
         } 
        }, 
        "as": "cls", 
        "cond": "$$cls" 
       } 
      } 
     }} 
    ] 
) 

In der kommenden MongoDB Mitteilung (als dies geschrieben wurde und seit MongoDB 3.3.5) können Sie ersetzen die $cond Ausdruck in der der $map Ausdruck mit einem $switch Ausdruck:

Permit.aggregate(
    [ 
     { "$match": { "_id": mongoose.Types.ObjectId(req.params.id) } }, 
     { "$project": { 
      "_updated": 1, 
      "_created": 1, 
      "name": 1, 
      "feeClassifications": { 
       "$filter": { 
        "input": { 
         "$map": { 
          "input": "$feeClassifications", 
          "as": "fclass", 
          "in": { 
           "$switch": { 
            "branches": [ 
             { 
              "case": { "$lt": [ "$$fclass._trashed", 0 ] }, 
              "then": { 
               "_updated": "$$fclass._updated", 
               "_created": "$$fclass._created", 
               "name": "$$fclass.name", 
               "_id": "$$fclass._id", 
               "fees": { 
                "$filter": { 
                 "input": "$$fclass.fees", 
                 "as": "fees", 
                 "cond": { "$lt": [ "$$fees._trashed", 0 ] } 
                } 
               } 
              } 
             } 
            ], 
            "default": false 
           } 
          } 
         } 
        }, 
        "as": "cls", 
        "cond": "$$cls" 
       } 
      } 
     }} 
    ] 
) 
+0

Ich konnte dir nicht genug danken! Danke für die informative Antwort und die Erklärungen. Das macht die Stunden, die ich damit verbracht habe, das herauszufinden, wert. – Joao